Product
Secret Sync
Describe the bug
disableSecretDeletion is enforced individually by each secret sync rather than centrally in secret-sync-fns.ts. Of the 44 destinations with a *-sync-fns.ts, 43 read the flag somewhere in their sync path. azure-devops is the only one whose sync functions never reference it at all:
$ grep -rn "disableSecretDeletion" backend/src/services/secret-sync/azure-devops/
$
The comparable destinations all guard their prune step, in one of a few shapes:
// vercel, 1password, databricks, ...
if (secretSync.syncOptions.disableSecretDeletion) return;
// aws-parameter-store, aws-secrets-manager
if (syncOptions.disableSecretDeletion) return { createdSecretKeys, updatedSecretKeys, deletedSecretKeys };
// gcp
if (secretSync.syncOptions.disableSecretDeletion) continue;
Why it matters here specifically
azure-devops-sync-fns.ts builds its payload from the Infisical secret map alone, then PUTs the whole variable group:
const variables: Record<string, { value: string; isSecret: boolean }> = {};
for (const [key, secret] of Object.entries(secretMap)) {
if (secret?.value !== undefined) {
variables[key] = { value: secret.value, isSecret: true };
}
}
...
await request.put(url, {
name: groupName,
description: groupName,
type: "Vsts",
variables,
variableGroupProjectReferences: [...]
}, { ... });
Nothing reads the existing group's variables first, so whatever the destination already had is not carried into the request body. The Update variable group reference describes the body field as "Sets variables contained in the variable group", which reads as replacement rather than merge on a PUT.
I could not verify the delete-on-omit behaviour against a real Azure DevOps organisation, so I am flagging rather than asserting it. Either reading is still a bug:
- If the PUT replaces, a user who enables "Disable Secret Deletion" still loses every variable in the group that is not managed by Infisical, which is the exact scenario the option exists to prevent.
- If the PUT merges, then this destination has no prune step at all, and the option is offered in the UI while doing nothing here.
To Reproduce
- Create an Azure DevOps secret sync and enable Disable Secret Deletion in the sync options.
- Add a variable directly in the destination variable group that does not exist in the Infisical environment.
- Trigger a sync.
- Check whether the manually added variable is still present.
Expected behavior
Same as every other destination: when disableSecretDeletion is set, a sync should not remove destination secrets that are absent from Infisical.
Additional context
Checked azure-entra-id-scim too, since it also has no reference to the flag in its sync functions, but it does not appear to have a prune step, so I do not think it is affected.
The wider observation is that the flag is reimplemented 43 separate times in at least seven different shapes. Enforcing it once around the prune step would make this class of gap impossible rather than relying on each new destination remembering. Happy to open a PR for the azure-devops case on its own, or for the centralisation if that is wanted, but the latter touches every destination so it seemed worth asking first.
Product
Secret Sync
Describe the bug
disableSecretDeletionis enforced individually by each secret sync rather than centrally insecret-sync-fns.ts. Of the 44 destinations with a*-sync-fns.ts, 43 read the flag somewhere in their sync path.azure-devopsis the only one whose sync functions never reference it at all:$ grep -rn "disableSecretDeletion" backend/src/services/secret-sync/azure-devops/ $The comparable destinations all guard their prune step, in one of a few shapes:
Why it matters here specifically
azure-devops-sync-fns.tsbuilds its payload from the Infisical secret map alone, then PUTs the whole variable group:Nothing reads the existing group's variables first, so whatever the destination already had is not carried into the request body. The Update variable group reference describes the body field as "Sets variables contained in the variable group", which reads as replacement rather than merge on a PUT.
I could not verify the delete-on-omit behaviour against a real Azure DevOps organisation, so I am flagging rather than asserting it. Either reading is still a bug:
To Reproduce
Expected behavior
Same as every other destination: when
disableSecretDeletionis set, a sync should not remove destination secrets that are absent from Infisical.Additional context
Checked
azure-entra-id-scimtoo, since it also has no reference to the flag in its sync functions, but it does not appear to have a prune step, so I do not think it is affected.The wider observation is that the flag is reimplemented 43 separate times in at least seven different shapes. Enforcing it once around the prune step would make this class of gap impossible rather than relying on each new destination remembering. Happy to open a PR for the
azure-devopscase on its own, or for the centralisation if that is wanted, but the latter touches every destination so it seemed worth asking first.