mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
# Backport This will backport the following commits from `main` to `8.11`: - [[Fleet] Improve UX for policy secrets (#171405)](https://github.com/elastic/kibana/pull/171405) <!--- Backport version: 8.9.8 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Kyle Pollich","email":"kyle.pollich@elastic.co"},"sourceCommit":{"committedDate":"2023-11-16T19:35:19Z","message":"[Fleet] Improve UX for policy secrets (#171405)\n\n## Summary\r\n\r\nCloses https://github.com/elastic/kibana/issues/171225\r\n\r\n- Highlights secrets during package policy creation with a distinct\r\nbackground and icon\r\n- Add tooltip + docs link for secrets where appropriate\r\n- Detect \"new secrets\" during policy upgrade and alert the user in a\r\nseparate callout\r\n\r\n## To do\r\n- [x] Fix any failing tests\r\n- [x] Add tests for \"new secrets\" detection logic\r\n\r\n## Screenshots\r\n\r\n\r\n\r\n\r\n## How to test\r\n\r\nThere's probably an easier way to do this, but this is what I did\r\n\r\n1. Clone https://github.com/elastic/package-registry and\r\nhttps://github.com/elastic/integrations\r\n2. Add the following to `config.yml` in your package-registry repo\r\n\r\n```yml\r\npackage_paths:\r\n - path/to/your/integrations/build/packages\r\n```\r\n\r\n3. Build a version of an integration with some `secrets: true` for\r\nvarious variables. I used `1password`\r\n\r\n```shell\r\ncd integrations/packages/1password\r\n# Edit `manifest.yml` or a given `data_stream/*/manifest.yml` file to change some variables to `secret: true`. Also bump the version and update `changelog.yml`\r\nelastic-package build\r\n```\r\n\r\n4. Run the local package registry e.g. \r\n\r\n```shell\r\ncd package-registry\r\ngo run . --feature-proxy-mode=true -proxy-to=https://epr.elastic.co # makes it so you can still see EPR packages in Kibana\r\n```\r\n\r\n5. Update your `kibana.dev.yml` to point at your local package registry\r\n\r\n```yml\r\nxpack.fleet.registryUrl: http://localhost:8080\r\n```\r\n\r\n6. Start Kibana and Elasticsearch and install, upgrade, etc your package\r\nin question to verify the changes\r\n\r\n---------\r\n\r\nCo-authored-by: David Kilfoyle <41695641+kilfoyle@users.noreply.github.com>","sha":"9396ef3d6bed213b681970a4914eeb558a30ed44","branchLabelMapping":{"^v8.12.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:enhancement","Team:Fleet","backport:prev-minor","v8.12.0"],"number":171405,"url":"https://github.com/elastic/kibana/pull/171405","mergeCommit":{"message":"[Fleet] Improve UX for policy secrets (#171405)\n\n## Summary\r\n\r\nCloses https://github.com/elastic/kibana/issues/171225\r\n\r\n- Highlights secrets during package policy creation with a distinct\r\nbackground and icon\r\n- Add tooltip + docs link for secrets where appropriate\r\n- Detect \"new secrets\" during policy upgrade and alert the user in a\r\nseparate callout\r\n\r\n## To do\r\n- [x] Fix any failing tests\r\n- [x] Add tests for \"new secrets\" detection logic\r\n\r\n## Screenshots\r\n\r\n\r\n\r\n\r\n## How to test\r\n\r\nThere's probably an easier way to do this, but this is what I did\r\n\r\n1. Clone https://github.com/elastic/package-registry and\r\nhttps://github.com/elastic/integrations\r\n2. Add the following to `config.yml` in your package-registry repo\r\n\r\n```yml\r\npackage_paths:\r\n - path/to/your/integrations/build/packages\r\n```\r\n\r\n3. Build a version of an integration with some `secrets: true` for\r\nvarious variables. I used `1password`\r\n\r\n```shell\r\ncd integrations/packages/1password\r\n# Edit `manifest.yml` or a given `data_stream/*/manifest.yml` file to change some variables to `secret: true`. Also bump the version and update `changelog.yml`\r\nelastic-package build\r\n```\r\n\r\n4. Run the local package registry e.g. \r\n\r\n```shell\r\ncd package-registry\r\ngo run . --feature-proxy-mode=true -proxy-to=https://epr.elastic.co # makes it so you can still see EPR packages in Kibana\r\n```\r\n\r\n5. Update your `kibana.dev.yml` to point at your local package registry\r\n\r\n```yml\r\nxpack.fleet.registryUrl: http://localhost:8080\r\n```\r\n\r\n6. Start Kibana and Elasticsearch and install, upgrade, etc your package\r\nin question to verify the changes\r\n\r\n---------\r\n\r\nCo-authored-by: David Kilfoyle <41695641+kilfoyle@users.noreply.github.com>","sha":"9396ef3d6bed213b681970a4914eeb558a30ed44"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v8.12.0","labelRegex":"^v8.12.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/171405","number":171405,"mergeCommit":{"message":"[Fleet] Improve UX for policy secrets (#171405)\n\n## Summary\r\n\r\nCloses https://github.com/elastic/kibana/issues/171225\r\n\r\n- Highlights secrets during package policy creation with a distinct\r\nbackground and icon\r\n- Add tooltip + docs link for secrets where appropriate\r\n- Detect \"new secrets\" during policy upgrade and alert the user in a\r\nseparate callout\r\n\r\n## To do\r\n- [x] Fix any failing tests\r\n- [x] Add tests for \"new secrets\" detection logic\r\n\r\n## Screenshots\r\n\r\n\r\n\r\n\r\n## How to test\r\n\r\nThere's probably an easier way to do this, but this is what I did\r\n\r\n1. Clone https://github.com/elastic/package-registry and\r\nhttps://github.com/elastic/integrations\r\n2. Add the following to `config.yml` in your package-registry repo\r\n\r\n```yml\r\npackage_paths:\r\n - path/to/your/integrations/build/packages\r\n```\r\n\r\n3. Build a version of an integration with some `secrets: true` for\r\nvarious variables. I used `1password`\r\n\r\n```shell\r\ncd integrations/packages/1password\r\n# Edit `manifest.yml` or a given `data_stream/*/manifest.yml` file to change some variables to `secret: true`. Also bump the version and update `changelog.yml`\r\nelastic-package build\r\n```\r\n\r\n4. Run the local package registry e.g. \r\n\r\n```shell\r\ncd package-registry\r\ngo run . --feature-proxy-mode=true -proxy-to=https://epr.elastic.co # makes it so you can still see EPR packages in Kibana\r\n```\r\n\r\n5. Update your `kibana.dev.yml` to point at your local package registry\r\n\r\n```yml\r\nxpack.fleet.registryUrl: http://localhost:8080\r\n```\r\n\r\n6. Start Kibana and Elasticsearch and install, upgrade, etc your package\r\nin question to verify the changes\r\n\r\n---------\r\n\r\nCo-authored-by: David Kilfoyle <41695641+kilfoyle@users.noreply.github.com>","sha":"9396ef3d6bed213b681970a4914eeb558a30ed44"}}]}] BACKPORT--> --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
05a2b882bb
commit
279c469047
12 changed files with 427 additions and 57 deletions
|
@ -767,6 +767,9 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => {
|
|||
agentPolicy: `${FLEET_DOCS}agent-policy.html`,
|
||||
api: `${FLEET_DOCS}fleet-api-docs.html`,
|
||||
uninstallAgent: `${SECURITY_SOLUTION_DOCS}uninstall-agent.html`,
|
||||
installAndUninstallIntegrationAssets: `${FLEET_DOCS}install-uninstall-integration-assets.html`,
|
||||
elasticAgentInputConfiguration: `${FLEET_DOCS}elastic-agent-input-configuration.html`,
|
||||
policySecrets: `${FLEET_DOCS}agent-policy.html#agent-policy-secret-values`,
|
||||
},
|
||||
ecs: {
|
||||
guide: `${ELASTIC_WEBSITE_URL}guide/en/ecs/current/index.html`,
|
||||
|
|
|
@ -525,6 +525,9 @@ export interface DocLinks {
|
|||
agentPolicy: string;
|
||||
api: string;
|
||||
uninstallAgent: string;
|
||||
installAndUninstallIntegrationAssets: string;
|
||||
elasticAgentInputConfiguration: string;
|
||||
policySecrets: string;
|
||||
}>;
|
||||
readonly ecs: {
|
||||
readonly guide: string;
|
||||
|
|
|
@ -23,11 +23,16 @@ import {
|
|||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiButtonEmpty,
|
||||
EuiLink,
|
||||
EuiToolTip,
|
||||
EuiIcon,
|
||||
} from '@elastic/eui';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { CodeEditor } from '@kbn/kibana-react-plugin/public';
|
||||
|
||||
import { useStartServices } from '../../../../../../../../hooks';
|
||||
|
||||
import { ExperimentalFeaturesService } from '../../../../../../services';
|
||||
|
||||
import { DATASET_VAR_NAME } from '../../../../../../../../../common/constants';
|
||||
|
@ -41,6 +46,16 @@ const FixedHeightDiv = styled.div`
|
|||
height: 300px;
|
||||
`;
|
||||
|
||||
const FormRow = styled(EuiFormRow)`
|
||||
.euiFormRow__label {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.euiFormRow__fieldWrapper > .euiPanel {
|
||||
padding: ${(props) => props.theme.eui.euiSizeXS};
|
||||
}
|
||||
`;
|
||||
|
||||
interface InputFieldProps {
|
||||
varDef: RegistryVarsEntry;
|
||||
value: any;
|
||||
|
@ -125,11 +140,11 @@ export const PackagePolicyInputVarField: React.FunctionComponent<InputFieldProps
|
|||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiFormRow
|
||||
const formRow = (
|
||||
<FormRow
|
||||
isInvalid={isInvalid}
|
||||
error={errors}
|
||||
label={fieldLabel}
|
||||
label={varDef.secret ? <SecretFieldLabel fieldLabel={fieldLabel} /> : fieldLabel}
|
||||
labelAppend={
|
||||
isOptional ? (
|
||||
<EuiText size="xs" color="subdued">
|
||||
|
@ -138,13 +153,16 @@ export const PackagePolicyInputVarField: React.FunctionComponent<InputFieldProps
|
|||
defaultMessage="Optional"
|
||||
/>
|
||||
</EuiText>
|
||||
) : null
|
||||
) : undefined
|
||||
}
|
||||
helpText={description && <ReactMarkdown children={description} />}
|
||||
fullWidth
|
||||
>
|
||||
{field}
|
||||
</EuiFormRow>
|
||||
</FormRow>
|
||||
);
|
||||
|
||||
return varDef.secret ? <SecretFieldWrapper>{formRow}</SecretFieldWrapper> : formRow;
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -296,6 +314,53 @@ function getInputComponent({
|
|||
}
|
||||
}
|
||||
|
||||
const SecretFieldWrapper = ({ children }: { children: React.ReactNode }) => {
|
||||
const { docLinks } = useStartServices();
|
||||
|
||||
return (
|
||||
<EuiPanel hasShadow={false} color="subdued" paddingSize="m">
|
||||
{children}
|
||||
|
||||
<EuiSpacer size="l" />
|
||||
|
||||
<EuiText size="xs">
|
||||
<EuiLink href={docLinks.links.fleet.policySecrets} target="_blank">
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.createPackagePolicy.stepConfigure.secretLearnMoreText"
|
||||
defaultMessage="Learn more about policy secrets."
|
||||
/>
|
||||
</EuiLink>
|
||||
</EuiText>
|
||||
</EuiPanel>
|
||||
);
|
||||
};
|
||||
|
||||
const SecretFieldLabel = ({ fieldLabel }: { fieldLabel: string }) => {
|
||||
return (
|
||||
<>
|
||||
<EuiFlexGroup alignItems="center" gutterSize="xs">
|
||||
<EuiFlexItem grow={true} aria-label={fieldLabel}>
|
||||
{fieldLabel}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiToolTip
|
||||
content={
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.createPackagePolicy.stepConfigure.secretLearnMorePopoverContent"
|
||||
defaultMessage="This value is a secret. After you save this integration policy, you won't be able to view the value again."
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiIcon aria-label="Secret value" type="questionInCircle" color="subdued" />
|
||||
</EuiToolTip>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
<EuiSpacer size="s" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
function SecretInputField({
|
||||
varDef,
|
||||
value,
|
||||
|
@ -313,10 +378,12 @@ function SecretInputField({
|
|||
}: InputComponentProps) {
|
||||
const [editMode, setEditMode] = useState(isEditPage && !value);
|
||||
const valueOnFirstRender = useRef(value);
|
||||
|
||||
const lowercaseTitle = varDef.title?.toLowerCase();
|
||||
|
||||
if (isEditPage && !editMode) {
|
||||
return (
|
||||
<EuiPanel color="subdued" borderRadius="none" hasShadow={false}>
|
||||
<>
|
||||
<EuiText size="s" color="subdued">
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.editPackagePolicy.stepConfigure.fieldSecretValueSet"
|
||||
|
@ -342,7 +409,7 @@ function SecretInputField({
|
|||
}}
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiPanel>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,10 +24,18 @@ import {
|
|||
EuiFlyoutBody,
|
||||
EuiFlyoutHeader,
|
||||
EuiTitle,
|
||||
EuiSpacer,
|
||||
} from '@elastic/eui';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import type {
|
||||
DryRunPackagePolicy,
|
||||
PackagePolicy,
|
||||
RegistryVarsEntry,
|
||||
} from '../../../../../../../common';
|
||||
|
||||
import type { UpgradePackagePolicyDryRunResponse } from '../../../../../../../common/types/rest_spec';
|
||||
import { useStartServices } from '../../../../hooks';
|
||||
|
||||
const FlyoutBody = styled(EuiFlyoutBody)`
|
||||
.euiFlyoutBody__overflowContent {
|
||||
|
@ -35,18 +43,125 @@ const FlyoutBody = styled(EuiFlyoutBody)`
|
|||
}
|
||||
`;
|
||||
|
||||
const HasNewSecretsCallOut = ({ newSecrets }: { newSecrets: RegistryVarsEntry[] }) => {
|
||||
const { docLinks } = useStartServices();
|
||||
|
||||
return (
|
||||
<EuiCallOut
|
||||
title={i18n.translate('xpack.fleet.upgradePackagePolicy.statusCallOut.hasNewSecretsTitle', {
|
||||
defaultMessage: 'New secrets added',
|
||||
})}
|
||||
color="primary"
|
||||
iconType="iInCircle"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.upgradePackagePolicy.statusCallout.hasNewSecrets"
|
||||
defaultMessage="Some of this integration's form fields have been converted to secrets in this version. Your existing values are autofilled in each secret input during this upgrade, but you won't be able to view them again after saving. {learnMoreLink}"
|
||||
values={{
|
||||
learnMoreLink: (
|
||||
<EuiLink href={docLinks.links.fleet.policySecrets} target="_blank">
|
||||
Learn more.
|
||||
</EuiLink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
|
||||
<EuiSpacer size="s" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.upgradePackagePolicy.statusCallout.hasNewSecretsList"
|
||||
defaultMessage="New secrets: {secrets}"
|
||||
values={{
|
||||
secrets: (
|
||||
<ul>
|
||||
{newSecrets.map((secret) => (
|
||||
<li key={secret.title}>{secret.title}</li>
|
||||
))}
|
||||
</ul>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</EuiCallOut>
|
||||
);
|
||||
};
|
||||
|
||||
const HasConflictsCallout = ({
|
||||
currentPackagePolicy,
|
||||
proposedUpgradePackagePolicy,
|
||||
onPreviousConfigurationClick,
|
||||
}: {
|
||||
currentPackagePolicy?: PackagePolicy;
|
||||
proposedUpgradePackagePolicy?: DryRunPackagePolicy;
|
||||
onPreviousConfigurationClick?: () => void;
|
||||
}) => {
|
||||
return (
|
||||
<EuiCallOut
|
||||
title={i18n.translate('xpack.fleet.upgradePackagePolicy.statusCallOut.errorTitle', {
|
||||
defaultMessage: 'Review field conflicts',
|
||||
})}
|
||||
color="warning"
|
||||
iconType="warning"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.upgradePackagePolicy.statusCallout.errorContent"
|
||||
defaultMessage="This integration has conflicting fields from version {currentVersion} to {upgradeVersion} Review the configuration and save to perform the upgrade. You may reference your {previousConfigurationLink} for comparison."
|
||||
values={{
|
||||
currentVersion: currentPackagePolicy?.package?.version,
|
||||
upgradeVersion: proposedUpgradePackagePolicy?.package?.version,
|
||||
previousConfigurationLink: (
|
||||
<EuiLink onClick={onPreviousConfigurationClick}>
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.upgradePackagePolicy.statusCallout.previousConfigurationLink"
|
||||
defaultMessage="previous configuration"
|
||||
/>
|
||||
</EuiLink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</EuiCallOut>
|
||||
);
|
||||
};
|
||||
|
||||
const ReadyToUpgradeCallOut = ({
|
||||
currentPackagePolicy,
|
||||
proposedUpgradePackagePolicy,
|
||||
}: {
|
||||
currentPackagePolicy?: PackagePolicy;
|
||||
proposedUpgradePackagePolicy?: DryRunPackagePolicy;
|
||||
}) => {
|
||||
return (
|
||||
<EuiCallOut
|
||||
title={i18n.translate('xpack.fleet.upgradePackagePolicy.statusCallOut.successTitle', {
|
||||
defaultMessage: 'Ready to upgrade',
|
||||
})}
|
||||
color="success"
|
||||
iconType="checkInCircleFilled"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.upgradePackagePolicy.statusCallout.successContent"
|
||||
defaultMessage="This integration is ready to be upgraded from version {currentVersion} to {upgradeVersion}. Review the changes below and save to upgrade."
|
||||
values={{
|
||||
currentVersion: currentPackagePolicy?.package?.version,
|
||||
upgradeVersion: proposedUpgradePackagePolicy?.package?.version,
|
||||
}}
|
||||
/>
|
||||
</EuiCallOut>
|
||||
);
|
||||
};
|
||||
|
||||
export const UpgradeStatusCallout: React.FunctionComponent<{
|
||||
dryRunData: UpgradePackagePolicyDryRunResponse;
|
||||
}> = ({ dryRunData }) => {
|
||||
newSecrets: RegistryVarsEntry[];
|
||||
}> = ({ dryRunData, newSecrets }) => {
|
||||
const [isPreviousVersionFlyoutOpen, setIsPreviousVersionFlyoutOpen] = useState<boolean>(false);
|
||||
|
||||
if (!dryRunData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isReadyForUpgrade = !dryRunData[0].hasErrors;
|
||||
|
||||
const hasNewSecrets = newSecrets.length > 0;
|
||||
const [currentPackagePolicy, proposedUpgradePackagePolicy] = dryRunData[0].diff || [];
|
||||
const isReadyForUpgrade = currentPackagePolicy && !dryRunData[0].hasErrors;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -73,48 +188,23 @@ export const UpgradeStatusCallout: React.FunctionComponent<{
|
|||
</EuiPortal>
|
||||
)}
|
||||
|
||||
{isReadyForUpgrade && currentPackagePolicy ? (
|
||||
<EuiCallOut
|
||||
title={i18n.translate('xpack.fleet.upgradePackagePolicy.statusCallOut.successTitle', {
|
||||
defaultMessage: 'Ready to upgrade',
|
||||
})}
|
||||
color="success"
|
||||
iconType="checkInCircleFilled"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.upgradePackagePolicy.statusCallout.successContent"
|
||||
defaultMessage="This integration is ready to be upgraded from version {currentVersion} to {upgradeVersion}. Review the changes below and save to upgrade."
|
||||
values={{
|
||||
currentVersion: currentPackagePolicy?.package?.version,
|
||||
upgradeVersion: proposedUpgradePackagePolicy?.package?.version,
|
||||
}}
|
||||
/>
|
||||
</EuiCallOut>
|
||||
{isReadyForUpgrade ? (
|
||||
<ReadyToUpgradeCallOut
|
||||
currentPackagePolicy={currentPackagePolicy}
|
||||
proposedUpgradePackagePolicy={proposedUpgradePackagePolicy}
|
||||
/>
|
||||
) : (
|
||||
<EuiCallOut
|
||||
title={i18n.translate('xpack.fleet.upgradePackagePolicy.statusCallOut.errorTitle', {
|
||||
defaultMessage: 'Review field conflicts',
|
||||
})}
|
||||
color="warning"
|
||||
iconType="warning"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.upgradePackagePolicy.statusCallout.errorContent"
|
||||
defaultMessage="This integration has conflicting fields from version {currentVersion} to {upgradeVersion} Review the configuration and save to perform the upgrade. You may reference your {previousConfigurationLink} for comparison."
|
||||
values={{
|
||||
currentVersion: currentPackagePolicy?.package?.version,
|
||||
upgradeVersion: proposedUpgradePackagePolicy?.package?.version,
|
||||
previousConfigurationLink: (
|
||||
<EuiLink onClick={() => setIsPreviousVersionFlyoutOpen(true)}>
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.upgradePackagePolicy.statusCallout.previousConfigurationLink"
|
||||
defaultMessage="previous configuration"
|
||||
/>
|
||||
</EuiLink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</EuiCallOut>
|
||||
<HasConflictsCallout
|
||||
currentPackagePolicy={currentPackagePolicy}
|
||||
proposedUpgradePackagePolicy={proposedUpgradePackagePolicy}
|
||||
onPreviousConfigurationClick={() => setIsPreviousVersionFlyoutOpen(true)}
|
||||
/>
|
||||
)}
|
||||
{hasNewSecrets && (
|
||||
<>
|
||||
<EuiSpacer size="m" />
|
||||
<HasNewSecretsCallOut newSecrets={newSecrets} />
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -99,7 +99,9 @@ export function usePackagePolicyWithRelatedData(
|
|||
policy: { elasticsearch, ...restPackagePolicy },
|
||||
} = await prepareInputPackagePolicyDataset(packagePolicy);
|
||||
const result = await sendUpdatePackagePolicy(packagePolicyId, restPackagePolicy);
|
||||
|
||||
setFormState('SUBMITTED');
|
||||
|
||||
return result;
|
||||
};
|
||||
// Update package policy validation
|
||||
|
|
|
@ -19,7 +19,6 @@ import {
|
|||
EuiErrorBoundary,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import type { PackageInfo } from '../../../types';
|
||||
import {
|
||||
useLink,
|
||||
useBreadcrumbs,
|
||||
|
@ -55,6 +54,7 @@ import { generateUpdatePackagePolicyDevToolsRequest } from '../services';
|
|||
|
||||
import { UpgradeStatusCallout } from './components';
|
||||
import { usePackagePolicyWithRelatedData, useHistoryBlock } from './hooks';
|
||||
import { getNewSecrets } from './utils';
|
||||
|
||||
export const EditPackagePolicyPage = memo(() => {
|
||||
const {
|
||||
|
@ -91,7 +91,6 @@ export const EditPackagePolicyForm = memo<{
|
|||
} = useConfig();
|
||||
const { getHref } = useLink();
|
||||
|
||||
const [] = useState<PackageInfo>();
|
||||
const {
|
||||
// data
|
||||
agentPolicy,
|
||||
|
@ -117,6 +116,14 @@ export const EditPackagePolicyForm = memo<{
|
|||
|
||||
const canWriteIntegrationPolicies = useAuthz().integrations.writeIntegrationPolicies;
|
||||
|
||||
const newSecrets = useMemo(() => {
|
||||
if (!packageInfo) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return getNewSecrets({ packageInfo, packagePolicy });
|
||||
}, [packageInfo, packagePolicy]);
|
||||
|
||||
const policyId = agentPolicy?.id ?? '';
|
||||
|
||||
// Retrieve agent count
|
||||
|
@ -418,7 +425,7 @@ export const EditPackagePolicyForm = memo<{
|
|||
)}
|
||||
{isUpgrade && upgradeDryRunData && (
|
||||
<>
|
||||
<UpgradeStatusCallout dryRunData={upgradeDryRunData} />
|
||||
<UpgradeStatusCallout dryRunData={upgradeDryRunData} newSecrets={newSecrets} />
|
||||
<EuiSpacer size="xxl" />
|
||||
</>
|
||||
)}
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { PackageInfo, UpdatePackagePolicy } from '../../../../types';
|
||||
|
||||
import { getNewSecrets } from './get_new_secrets';
|
||||
|
||||
describe('getNewSecrets', () => {
|
||||
it('does not find new secrets when there are no secrets configured', () => {
|
||||
const packageInfo = {
|
||||
name: 'mock-package',
|
||||
title: 'Mock package',
|
||||
version: '0.0.0',
|
||||
vars: [
|
||||
{
|
||||
name: 'package-var',
|
||||
type: 'string',
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
policy_templates: [
|
||||
{
|
||||
name: 'test-policy-template',
|
||||
inputs: [
|
||||
{
|
||||
type: 'test-input',
|
||||
title: 'Test input',
|
||||
description: 'Test input',
|
||||
vars: [
|
||||
{
|
||||
name: 'policy-template-var',
|
||||
type: 'string',
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
} as unknown as PackageInfo;
|
||||
|
||||
const packagePolicy = {
|
||||
vars: [
|
||||
{
|
||||
name: 'package-var',
|
||||
value: 'test',
|
||||
},
|
||||
],
|
||||
inputs: [
|
||||
{
|
||||
name: 'test-input',
|
||||
vars: {
|
||||
'policy-template-var': {
|
||||
value: 'test',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
} as unknown as UpdatePackagePolicy;
|
||||
|
||||
expect(
|
||||
getNewSecrets({
|
||||
packageInfo,
|
||||
packagePolicy,
|
||||
})
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it('finds new secrets when they exist', () => {
|
||||
const packageInfo = {
|
||||
name: 'mock-package',
|
||||
title: 'Mock package',
|
||||
version: '0.0.0',
|
||||
vars: [
|
||||
{
|
||||
name: 'package-var',
|
||||
type: 'string',
|
||||
secret: true,
|
||||
},
|
||||
],
|
||||
policy_templates: [
|
||||
{
|
||||
name: 'test-policy-template',
|
||||
inputs: [
|
||||
{
|
||||
type: 'test-input',
|
||||
title: 'Test input',
|
||||
description: 'Test input',
|
||||
vars: [
|
||||
{
|
||||
name: 'policy-template-var',
|
||||
type: 'string',
|
||||
secret: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
} as unknown as PackageInfo;
|
||||
|
||||
const packagePolicy = {
|
||||
vars: [
|
||||
{
|
||||
name: 'package-var',
|
||||
value: 'test',
|
||||
},
|
||||
],
|
||||
inputs: [
|
||||
{
|
||||
name: 'test-input',
|
||||
vars: {
|
||||
'policy-template-var': {
|
||||
value: 'test',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
} as unknown as UpdatePackagePolicy;
|
||||
|
||||
expect(
|
||||
getNewSecrets({
|
||||
packageInfo,
|
||||
packagePolicy,
|
||||
})
|
||||
).toEqual([
|
||||
{
|
||||
name: 'package-var',
|
||||
secret: true,
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
name: 'policy-template-var',
|
||||
secret: true,
|
||||
type: 'string',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { isInputOnlyPolicyTemplate } from '../../../../../../../common/services';
|
||||
|
||||
import type { PackageInfo, UpdatePackagePolicy } from '../../../../types';
|
||||
|
||||
export const getNewSecrets = ({
|
||||
packageInfo,
|
||||
packagePolicy,
|
||||
}: {
|
||||
packageInfo: PackageInfo;
|
||||
packagePolicy: UpdatePackagePolicy;
|
||||
}) => {
|
||||
const result = [];
|
||||
|
||||
for (const packageVar of packageInfo.vars ?? []) {
|
||||
const isVarSecretOnPolicy = packagePolicy.vars?.[packageVar.name]?.value?.isSecretRef;
|
||||
|
||||
if (packageVar.secret && !isVarSecretOnPolicy) {
|
||||
result.push(packageVar);
|
||||
}
|
||||
}
|
||||
|
||||
for (const policyTemplate of packageInfo.policy_templates ?? []) {
|
||||
if (isInputOnlyPolicyTemplate(policyTemplate)) {
|
||||
for (const packageVar of policyTemplate.vars ?? []) {
|
||||
const isVarSecretOnPolicy =
|
||||
packagePolicy.inputs?.[0]?.vars?.[packageVar.name]?.value?.isSecretRef;
|
||||
|
||||
if (packageVar.secret && !isVarSecretOnPolicy) {
|
||||
result.push(packageVar);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const input of policyTemplate.inputs ?? []) {
|
||||
for (const packageVar of input.vars ?? []) {
|
||||
const isVarSecretOnPolicy =
|
||||
packagePolicy.inputs?.[0]?.vars?.[packageVar.name]?.value?.isSecretRef;
|
||||
|
||||
if (packageVar.secret && !isVarSecretOnPolicy) {
|
||||
result.push(packageVar);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
|
@ -7,3 +7,4 @@
|
|||
|
||||
export * from './has_upgrade_available';
|
||||
export { fixApmDurationVars } from './fix_apm_duration_vars';
|
||||
export * from './get_new_secrets';
|
||||
|
|
|
@ -43728,10 +43728,10 @@
|
|||
"observabilityAlertDetails.alertThresholdTimeRangeRect.detailsTooltip": "Seuil",
|
||||
"randomSampling.ui.sliderControl.accuracyLabel": "Précision",
|
||||
"randomSampling.ui.sliderControl.performanceLabel": "Performances",
|
||||
"reactPackages.mountPointPortal.errorMessage": "Erreur lors du rendu du contenu du portail.",
|
||||
"reporting.common.browserCouldNotLaunchErrorMessage": "Impossible de générer des captures d'écran, car le navigateur ne s’est pas lancé. Consultez les logs de serveur pour en savoir plus.",
|
||||
"reporting.common.cloud.insufficientSystemMemoryError": "Impossible de générer ce rapport en raison d’un manque de mémoire.",
|
||||
"reporting.common.pdfWorkerOutOfMemoryErrorMessage": "Impossible de générer un PDF en raison d’un manque de mémoire. Essayez de réduire la taille du PDF et relancez ce rapport.",
|
||||
"reactPackages.mountPointPortal.errorMessage": "Erreur lors du rendu du contenu du portail.",
|
||||
"savedObjectsFinder.advancedSettings.listingLimitText": "Nombre d'objets à récupérer pour les pages de listing",
|
||||
"savedObjectsFinder.advancedSettings.listingLimitTitle": "Limite de listing d’objets",
|
||||
"savedObjectsFinder.advancedSettings.perPageText": "Nombre d'objets à afficher par page dans la boîte de dialogue de chargement",
|
||||
|
|
|
@ -43718,10 +43718,10 @@
|
|||
"observabilityAlertDetails.alertThresholdTimeRangeRect.detailsTooltip": "しきい値",
|
||||
"randomSampling.ui.sliderControl.accuracyLabel": "精度",
|
||||
"randomSampling.ui.sliderControl.performanceLabel": "パフォーマンス",
|
||||
"reactPackages.mountPointPortal.errorMessage": "ポータルコンテンツのレンダリングエラー",
|
||||
"reporting.common.browserCouldNotLaunchErrorMessage": "ブラウザーが起動していないため、スクリーンショットを生成できません。詳細については、サーバーログを参照してください。",
|
||||
"reporting.common.cloud.insufficientSystemMemoryError": "メモリ不足のため、このレポートを生成できません。",
|
||||
"reporting.common.pdfWorkerOutOfMemoryErrorMessage": "メモリ不足のため、PDFを生成できません。PDFのサイズを小さくして、このレポートを再試行してください。",
|
||||
"reactPackages.mountPointPortal.errorMessage": "ポータルコンテンツのレンダリングエラー",
|
||||
"savedObjectsFinder.advancedSettings.listingLimitText": "一覧ページ用に取得するオブジェクトの数です",
|
||||
"savedObjectsFinder.advancedSettings.listingLimitTitle": "オブジェクト取得制限",
|
||||
"savedObjectsFinder.advancedSettings.perPageText": "読み込みダイアログで表示されるページごとのオブジェクトの数です",
|
||||
|
|
|
@ -43712,10 +43712,10 @@
|
|||
"observabilityAlertDetails.alertThresholdTimeRangeRect.detailsTooltip": "阈值",
|
||||
"randomSampling.ui.sliderControl.accuracyLabel": "准确性",
|
||||
"randomSampling.ui.sliderControl.performanceLabel": "性能",
|
||||
"reactPackages.mountPointPortal.errorMessage": "呈现门户内容时出错",
|
||||
"reporting.common.browserCouldNotLaunchErrorMessage": "无法生成屏幕截图,因为浏览器未启动。有关更多信息,请查看服务器日志。",
|
||||
"reporting.common.cloud.insufficientSystemMemoryError": "由于内存不足,无法生成此报告。",
|
||||
"reporting.common.pdfWorkerOutOfMemoryErrorMessage": "由于内存不足,无法生成 PDF。尝试生成更小的 PDF,然后重试此报告。",
|
||||
"reactPackages.mountPointPortal.errorMessage": "呈现门户内容时出错",
|
||||
"savedObjectsFinder.advancedSettings.listingLimitText": "要为列表页面提取的对象数目",
|
||||
"savedObjectsFinder.advancedSettings.listingLimitTitle": "对象列表限制",
|
||||
"savedObjectsFinder.advancedSettings.perPageText": "加载对话框中每页要显示的对象数目",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue