fix: batch encryption-key rotation into one git-sync job#9355
Conversation
When changing a workspace encryption key, the secret variables get re-encrypted with the new key, but the git sync was only dispatched for the encryption_key.yaml metadata file. Repos with Secrets sync enabled were left with stale ciphertexts until the next per-variable deployment. Now, after the transaction commits, we also dispatch a Variable git sync event for each re-encrypted secret so the new encrypted values are pushed to the configured repos. Errors are logged but don't roll back the key rotation. Fixes WIN-1994 Fixes #9344 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Deploying windmill with
|
| Latest commit: |
5c6efd1
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://089b09bf.windmill.pages.dev |
| Branch Preview URL: | https://ruben-win-1994-fix-httpsgith.windmill.pages.dev |
|
Claude finished @rubenfiszel's task in 2m 30s —— View job VerdictMergeable, but should ideally address nits: dead error-handling branch + minor The fix is correct: when an encryption key rotates and FindingsP2 — dead
So the for path in reencrypted_secret_paths {
handle_deployment_metadata(
&authed.email,
&authed.username,
&db,
&w_id,
DeployedObject::Variable { path: path.clone(), parent_path: Some(path) },
Some("Variable re-encrypted after workspace key rotation".to_string()),
true,
None,
)
.await?;
}This is consistent with P2 — redundant The AGENTS.md compliance
Test coverage
|
Pi ReviewGood to merge What this PR doesWhen a workspace encryption key is rotated, all secret variables are re-encrypted inside a single transaction. Before this change, only an FindingsNo blocking issues or nits. The diff is clean and well-contained:
Test coverageThis is a backend handler enhancement with no new utility functions to unit-test and no API surface change. Integration-level testing of the git-sync dispatch loop would require a full git-sync EE stack, which is impractical for a unit test. Manual verification needed (as the PR's test plan already outlines): In a workspace with Git Sync + Secrets sync enabled, rotate the encryption key and confirm that one git-sync job is dispatched per re-encrypted secret variable (plus one for |
Codex ReviewGood to merge No issues found. Checked for bugs, security issues, performance regressions, and AGENTS.md compliance. Test coverageNo automated tests were added in this diff. For this backend git-sync behavior, the main manual verification is rotating a workspace encryption key with Git Sync configured for variables and secrets, then confirming the resulting sync job includes the re-encrypted secret variable ciphertexts. There is no separate frontend surface changed by this PR. |
Workspace encryption key rotation now re-encrypts every secret variable and then dispatches a single batched git-sync job carrying the Key event plus one Variable item per re-encrypted secret. Repos with Secrets sync enabled receive every new ciphertext in one commit instead of nothing (previously only `encryption_key.yaml` was pushed) — and instead of N separate jobs the debouncer might or might not merge. Wires through the new `handle_deployment_metadata_batch` entry point added in the companion EE PR; OSS has a no-op shim so the build stays green. Adds an integration test (`workspace_encryption_key_git_sync`) asserting that rotating the key with 3 secret variables in scope produces exactly one deployment-callback job whose `items` array contains the Key event + all 3 variable entries and `skip_secret=false`. Fixes WIN-1994 Fixes #9344 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pi ReviewGood to merge What this PR doesWhen a workspace encryption key is rotated, all secret variables are re-encrypted inside a single transaction. Before this change, only an FindingsNo blocking issues or nits. The diff is well-contained across two commits:
Key points from the current state of the diff:
AGENTS.md compliance
Test coverage
|
There was a problem hiding this comment.
1 issue found across 5 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="backend/windmill-api-workspaces/src/workspaces.rs">
<violation number="1" location="backend/windmill-api-workspaces/src/workspaces.rs:3474">
P2: Do not propagate post-commit git-sync batch errors; log them instead so key rotation success is not reported as a failed request.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
| handle_deployment_metadata_batch( | ||
| &authed.email, | ||
| &authed.username, | ||
| &db, | ||
| &w_id, | ||
| windmill_git_sync::DeployedObject::Key { key_type: "encryption_key".to_string() }, | ||
| batch, | ||
| Some("Encryption key updated".to_string()), | ||
| false, | ||
| None, | ||
| ) | ||
| .await?; |
There was a problem hiding this comment.
P2: Do not propagate post-commit git-sync batch errors; log them instead so key rotation success is not reported as a failed request.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/windmill-api-workspaces/src/workspaces.rs, line 3474:
<comment>Do not propagate post-commit git-sync batch errors; log them instead so key rotation success is not reported as a failed request.</comment>
<file context>
@@ -3458,43 +3461,26 @@ async fn set_encryption_key(
+ batch.push(DeployedObject::Variable { path: path.clone(), parent_path: Some(path) });
+ }
+
+ handle_deployment_metadata_batch(
&authed.email,
&authed.username,
</file context>
| handle_deployment_metadata_batch( | |
| &authed.email, | |
| &authed.username, | |
| &db, | |
| &w_id, | |
| windmill_git_sync::DeployedObject::Key { key_type: "encryption_key".to_string() }, | |
| batch, | |
| Some("Encryption key updated".to_string()), | |
| false, | |
| None, | |
| ) | |
| .await?; | |
| if let Err(e) = handle_deployment_metadata_batch( | |
| &authed.email, | |
| &authed.username, | |
| &db, | |
| &w_id, | |
| batch, | |
| Some("Encryption key updated".to_string()), | |
| ) | |
| .await | |
| { | |
| tracing::error!( | |
| "Failed to trigger git sync batch after workspace key rotation for {}: {}", | |
| w_id, | |
| e | |
| ); | |
| } |
Codex Reviewcc @rubenfiszel Should address issues before merging: git sync skipped without debouncing support Found 1 issue:
Test coverageBackend coverage improved with an enterprise/private integration test for the debounced happy path: one callback job containing the key plus all re-encrypted secret variables. The missing coverage is the compatibility path above: a repo using an older sync script, or an instance where sync-job debouncing is not available. Manual verification before merge should include rotating a workspace encryption key with Git Sync enabled on an older sync script and confirming a deployment callback is still queued and the repo receives the updated |
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codex Reviewcc @rubenfiszel Should address issues before merging: git sync skipped without debouncing support Found 1 issue:
Test coverageBackend coverage now includes the enterprise/private happy path where one debounced callback job carries the key plus all re-encrypted variables. The missing coverage is the compatibility path above: an older sync script or workers without sync-job debouncing support. Manual verification before merge should include rotating a workspace encryption key with Git Sync enabled on an older sync script and confirming a deployment callback is still queued and the repo receives the updated |
|
Now I have all the context I need. Let me write the final review. Pi Reviewcc @rubenfiszel Should address issues before merging: batch path silently drops git sync for repos lacking debouncing support FindingsP1 — Before this PR, After this PR, let supports_debouncing = workspace_git_repo.is_script_meets_min_version(28103)?
&& MIN_VERSION_SUPPORTS_SYNC_JOBS_DEBOUNCING.met().await;
if !supports_debouncing {
tracing::warn!("Batch git sync requires sync-job debouncing support …; skipping batch dispatch");
continue; // repo completely skipped — no job queued
}There is no fallback The integration test ( Suggested approach: restore a fallback when debouncing is unavailable. Options, in order of preference:
AGENTS.md complianceNo Test coverage
|
|
/ai review |
|
Claude finished @rubenfiszel's task in 3m 29s —— View job Review: PR #9355Verdict: Request changes — the batch-only dispatch introduces a real regression for repos without sync-job debouncing support (the P1 Codex and Pi have flagged across the last three review rounds is still unaddressed by the The core fix is correct and well-scoped: P1 (blocking) — key rotation can now queue zero git-sync jobs on older sync scripts
Before this PR, After this PR, everything flows through let supports_debouncing = workspace_git_repo.is_script_meets_min_version(28103)?
&& MIN_VERSION_SUPPORTS_SYNC_JOBS_DEBOUNCING.met().await;
if !supports_debouncing {
tracing::warn!("... skipping batch dispatch");
continue; // repo skipped entirely — no job queued
}There is no
Suggested fix: restore a fallback in the EE P2 — post-commit batch error propagated as a request failure
Caveat: the old code also used if let Err(e) = handle_deployment_metadata_batch(...).await {
tracing::error!("Failed to trigger git sync batch after key rotation for {w_id}: {e}");
}Test coverageThe new integration test (
|
Adds a regression test exercising a workspace whose sync script predates hub version 28103: the rotation must still queue a legacy-format deployment-callback job per item (encryption_key + each re-encrypted secret) instead of silently skipping the repo. Bumps ee-repo-ref to the EE fallback fix. Addresses the P1 raised in the PR review (Codex/Pi/Claude): batch path dropped git sync entirely for repos without sync-job debouncing support. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Addressed the review findings: P1 (blocking) — batch path skipped repos without debouncing support → key rotation queued zero jobs on older sync scripts. Fixed in the EE Added a regression test Also extracted a shared P2 — post-commit |
Codex Reviewcc @rubenfiszel Found 1 issue:
Test coverageBackend: the PR adds integration coverage for both batched git-sync dispatch and the legacy fallback path, which is the right layer for this behavior. The remaining blocker is making those tests compile under the repository’s offline SQLx CI setup. Manual verification still worth doing before merge: rotate a workspace encryption key with Git Sync configured for variables, secrets, and keys, then confirm the queued deployment callback includes the key plus every re-encrypted secret variable and that the target repo receives the updated ciphertexts. |
…tpsgithubcomwindmill-labswindmillissues9344 # Conflicts: # backend/ee-repo-ref.txt
Codex Reviewcc @rubenfiszel Should address issues before merging: missing SQLx offline cache for new integration test queries Found 1 issue:
Test coverageBackend coverage is now at the right layer: the PR adds enterprise/private integration tests for both the batched git-sync path and the legacy non-debounced fallback path. The remaining blocker is making those tests compile under the repository’s SQLx cache requirements. Manual verification before merge should still cover rotating a workspace encryption key with Git Sync configured for variables, secrets, and keys, then confirming the queued callback contains the encryption key plus every re-encrypted secret and that the target repo receives the updated ciphertexts. |
Pi Reviewcc @rubenfiszel Should address issues before merging: missing SQLx offline cache for new integration test queries FindingsP1 — The new test file uses compile-time-checked SQL macros that require Two queries are unaccounted for:
(The This also violates AGENTS.md step 4 ( Fix: run AGENTS.md complianceThe code changes are clean:
Test coverage
|
Pi Reviewcc @rubenfiszel Should address issues before merging: missing SQLx offline cache for 2 new checked queries in integration test FindingsP1 — The new test file uses compile-time-checked Two queries need new cache entries:
This violates AGENTS.md step 4, which defers to Fix: run Code quality assessmentThe logic changes are solid:
No Test coverage
|
|
…tpsgithubcomwindmill-labswindmillissues9344 # Conflicts: # backend/ee-repo-ref.txt
|
I have all the context needed. Let me write the final review. Pi Reviewcc @rubenfiszel Should address issues before merging: missing SQLx offline cache for 2 new checked queries in integration test FindingsP1 — The new test file uses compile-time-checked SQL macros ( Two queries need new cache entries:
(The This violates Fix: run Code quality assessmentThe logic changes are correct and well-structured:
No Test coverage
|
Codex Reviewcc @rubenfiszel Should address issues before merging: missing SQLx offline cache for new integration test queries Found 1 issue:
Test coverageBackend coverage is otherwise well targeted: the PR adds enterprise/private integration tests for both the batched git-sync path and the legacy non-debounced fallback path. The remaining blocker is making those tests compile under the repository’s SQLx offline-cache CI setup. Manual verification should still cover rotating a workspace encryption key with Git Sync configured for variables, secrets, and keys, then confirming the queued callback includes the encryption key plus every re-encrypted secret variable and that the target repo receives the updated ciphertexts. |
…bswindmillissues9344
Pi Reviewcc @rubenfiszel Should address issues before merging: missing SQLx offline cache for 2 new checked queries in integration test FindingsP1 — The new test uses compile-time-checked SQL macros, but the PR diff contains zero changes under Two queries need new cache entries:
This violates Fix: run Code quality assessmentThe logic changes are correct and well-structured:
No Test coverage
|
Codex Reviewcc @rubenfiszel Should address issues before merging: missing SQLx offline cache for new integration test queries Found 1 issue:
Test coverageBackend coverage is otherwise well targeted: the PR adds enterprise/private integration tests for both the batched git-sync path and the legacy non-debounced fallback path. The remaining blocker is making those tests compile under the repository’s SQLx offline-cache CI setup. Manual verification should still cover rotating a workspace encryption key with Git Sync configured for variables, secrets, and keys, then confirming the queued callback includes the encryption key plus every re-encrypted secret variable and that the target repo receives the updated ciphertexts. |
The cargo_test CI job builds with SQLX_OFFLINE=true; the two new sqlx::query!/query_as! calls in windmill-api-integration-tests/tests/workspace_encryption_key_git_sync.rs had no cached entries, failing the build with E0282. Regenerated and added only the two new query caches (no EE/feature cache loss). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Now I have all the context. Let me write the final review. Pi ReviewGood to merge What this PR doesWhen a workspace encryption key is rotated, all secret variables are re-encrypted inside a single transaction. Before this change, only an FindingsNo blocking issues or nits. The diff is well-contained across 7 commits, and all issues raised in prior review rounds have been addressed:
Code quality assessment:
AGENTS.md compliance
Test coverage
|
Codex ReviewGood to merge No issues found. Checked for bugs, security issues, performance regressions, prior Codex findings, AGENTS.md compliance, and the current head diff. Test coverageBackend coverage is included via the new enterprise/private integration tests for both the batched git-sync path and the non-debouncing legacy fallback, with SQLx offline cache entries added for the new queries. Manual verification before merge should rotate a workspace encryption key with Git Sync and Secrets sync enabled, then confirm the configured repo receives |
…bswindmillissues9344
|
I have thoroughly reviewed the full diff, the EE implementation of Pi ReviewGood to merge What this PR doesWhen a workspace encryption key is rotated, all secret variables are re-encrypted inside a single transaction. Before this change, only an Prior issues — all resolved
Code quality
AGENTS.md compliance
Test coverage
|
Codex ReviewGood to merge. No issues found. Checked the current head diff, AGENTS.md/REVIEW.md policy, the prior non-debouncing finding, and the added SQLx cache entries. Test coverageBackend coverage is well targeted: the PR adds enterprise/private integration tests for both the debounced batched git-sync path and the legacy non-debouncing fallback, with SQLx offline cache entries now present for the new checked queries. Manual verification before merge should rotate a workspace encryption key with Git Sync configured for keys, variables, and secrets, then confirm the repo receives |
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pi ReviewGood to merge What this PR doesWhen a workspace encryption key is rotated, all secret variables are re-encrypted inside a single transaction. Before this change, only an Prior issues — all resolved
Code quality assessment
AGENTS.md compliance
Test coverage
|
Codex ReviewGood to merge No issues found. The prior P1 is addressed: the EE batch path now falls back to legacy per-item jobs when sync-job debouncing is unavailable, and the added regression test covers that path. Test coverageBackend coverage looks appropriate: the PR adds enterprise/private integration tests for both the batched debouncing path and the older-script fallback path. I did not rerun the test suite during this read-only review. Manual verification before merge should rotate a workspace encryption key with Git Sync + Secrets sync enabled and confirm the repo receives |
|
/ai review this PR |
…bswindmillissues9344
|
Claude finished @rubenfiszel's task in 2m 58s —— View job Review: PR #9355Verdict: Good to merge. The fix is correct and well-scoped, and every blocking issue raised across the prior review rounds is now resolved. The one still-open inline comment (cubic P2 on the post-commit Correctness
Prior P1s — both resolved
Residual discussion point (non-blocking)cubic P2 — post-commit
Test coverageTwo integration tests gated behind
|
Pi ReviewGood to merge What this PR doesWhen a workspace encryption key is rotated, all secret variables are re-encrypted inside a single transaction. Before this change, only an Prior issues — all resolved
Code quality assessment
AGENTS.md compliance
Test coverage
|
Codex ReviewGood to merge No issues found. Checked the current head diff, prior review discussion, AGENTS.md/REVIEW.md compliance, and the EE batch fallback reflected by the updated Test coverageBackend coverage is appropriate: the PR adds enterprise/private integration tests for both the batched git-sync path and the legacy non-debouncing fallback, and the SQLx offline cache entries for the new checked queries are now present. I did not rerun the test suite during this read-only review. Manual verification before merge should rotate a workspace encryption key with Git Sync + Secrets sync enabled and confirm the repo receives |
Summary
Workspace encryption key rotation re-encrypts every secret variable
inside one transaction, but the post-commit git-sync dispatch only fired
a
DeployedObject::Keyevent forencryption_key.yaml. Repos withSecrets sync enabled were left with the old ciphertexts on disk until
each variable was individually deployed again.
This PR:
handle_deployment_metadata_batchtowindmill-git-sync(EEimplementation in the companion PR, OSS no-op shim). It looks up the
repo settings once, runs each
DeployedObjectthrough the existingpath/type filters, and pushes one git-sync job per
(repo, debounce_key)bucket carrying every item in theitemsarray.
group_by_folder: one job per folder.reliance on the debouncer's 5–15s merge window).
skip_secretonce per repo whenever the batch contains at leastone Variable, so the hub script knows whether to write decrypted
values for any of the included secrets.
set_encryption_keyto build a single batch[Key, Variable(p1), Variable(p2), …]and dispatch it through thenew entry point.
The single-object
handle_deployment_metadatapath is untouched.Companion EE PR
windmill-ee-privatebranch:ruben/win-1994-fix-httpsgithubcomwindmill-labswindmillissues9344HEAD:
108b0e2257d2df18b043802f88e945f9d3f0edf1Test plan
cargo check --features enterprise,private— clean (3 unrelated pre-existing warnings only)cargo test -p windmill-api-integration-tests --test workspace_encryption_key_git_sync --features enterprise,privateinclude_typeand inserts 3 secret variables/workspaces/encryption_keywith a new keyitemsarray contains thekeyentry + all 3variableentries withskip_secret=falseworkspaces,workspace_dependencies_git_syncFixes WIN-1994
Fixes #9344
🤖 Generated with Claude Code