feat: add --syncvalues flag and improve secret sharing #5

Open
dannygroenewegen wants to merge 2 commits from eCommons/alakazam:secret-sync into main
First-time contributor
  • Add --syncvalues flag to secrets command to update secret values from source to target apps (with redeploy of target app). Without --syncvalues, log a warning when values differ.
  • Fix bidirectionality: when source is missing its secret but target has one, warn instead of silently copying back and potentially overwriting the source value
  • Add get_secret_from_host fallback for distroless containers that reads the secret from the Docker host filesystem over SSH
  • Run secret hooks for all apps before any secret exchange to ensure source secrets are available before syncing to target app
- Add --syncvalues flag to secrets command to update secret values from source to target apps (with redeploy of target app). Without --syncvalues, log a warning when values differ. - Fix bidirectionality: when source is missing its secret but target has one, warn instead of silently copying back and potentially overwriting the source value - Add get_secret_from_host fallback for distroless containers that reads the secret from the Docker host filesystem over SSH - Run secret hooks for all apps before any secret exchange to ensure source secrets are available before syncing to target app
dannygroenewegen added 2 commits 2026-04-14 14:15:29 +00:00
- Resolve ABRA_DIR using env var or abra.yml instead of hardcoding ~/.abra
- Add ABRA_DIR to exclude_paths when inside root
- Add --syncvalues flag to secrets command to update secret values from source to target apps (with redeploy of target app). Without --syncvalues, log a warning when values differ.
- Fix bidirectionality: when source is missing its secret but target has one, warn instead of silently copying back and potentially overwriting the source value
- Add get_secret_from_host fallback for distroless containers that reads the secret from the Docker host filesystem over SSH
- Run secret hooks for all apps before any secret exchange to ensure source secrets are available before syncing to target app
simon requested review from simon 2026-05-07 11:29:14 +00:00
simon requested review from moritz 2026-05-07 11:29:14 +00:00
moritz requested changes 2026-05-11 15:08:39 +00:00
moritz left a comment
Owner

WHOOYAA! this PR contains some features I was really missing! Thank you a lot. Especially the get_secret_from_host() function I like! Hopefully it can be replaced someday by abra directly: toolshed/abra#694
Maybe this function can be extended to read the secrets, even if there are no running containers: toolshed/organising#480 (comment) but this could be somewhat for another issue.

WHOOYAA! this PR contains some features I was really missing! Thank you a lot. Especially the `get_secret_from_host()` function I like! Hopefully it can be replaced someday by abra directly: https://git.coopcloud.tech/toolshed/abra/issues/694 Maybe this function can be extended to read the secrets, even if there are no running containers: https://git.coopcloud.tech/toolshed/organising/issues/480#issuecomment-27767 but this could be somewhat for another issue.
@ -552,2 +574,2 @@
insert_secret(app1_domain, app1_secret, secret)
logging.info(f"Shared secret {app2_secret} from {app2_domain} to {app1_domain} as {app1_secret}")
# Target has secret but source doesn't, warn instead of copying back.
# Copying target to source risks overwriting the correct source value.
Owner

I'm not sure how you argue to remove the bidirectional secret sharing? The order which app is source or target should be quite irrelevant.
The condition app2_secret_is_stored and not app1_secret_is_stored: ensures, that no secret will be overwritten. Because the secret of app1 doesn't exists.

I'm not sure how you argue to remove the bidirectional secret sharing? The order which app is source or target should be quite irrelevant. The condition `app2_secret_is_stored and not app1_secret_is_stored:` ensures, that no secret will be overwritten. Because the secret of app1 doesn't exists.
@ -558,0 +595,4 @@
except RuntimeError as e:
logging.warning(f"Could not read secret for comparison ({app1_domain}/{app2_domain}): {e}")
continue
if app2_value is None or app1_value != app2_value:
Owner

Maybe it should be stated somewhere, that the secret of app2 will be overwritten, not only if it differs from the secret of app1, but also if the container is not running. The result will be the same, but for clarity.

Maybe it should be stated somewhere, that the secret of app2 will be overwritten, not only if it differs from the secret of app1, but also if the container is not running. The result will be the same, but for clarity.
@ -558,0 +603,4 @@
update_secret(app2_domain, app2_secret, app1_value, app2_container)
else:
logging.warning(
f"Secret mismatch: {app1_domain}/{app1_secret} differs from "
Owner

Here you should adapt the warning if the container is not running, because if it is not, the warning Secret mismatch: {app1_domain}/{app1_secret} differs from... would be incorrect. Instead a message like couldn't compare secret values, because {app1} is not running would be good.

Here you should adapt the warning if the container is not running, because if it is not, the warning `Secret mismatch: {app1_domain}/{app1_secret} differs from...` would be incorrect. Instead a message like `couldn't compare secret values, because {app1} is not running` would be good.
@ -579,0 +652,4 @@
if server:
break
if not server:
raise RuntimeError(f"Could not determine server for {domain}")
Owner

Instead of this for loop, you could use get_server_apps()

Instead of this for loop, you could use `get_server_apps()`
@ -665,6 +775,23 @@ def insert_secret(domain: str, secret_name: str, secret: str) -> None:
abra("app", "secret", "insert", domain, secret_name, "v1", secret)
def update_secret(domain: str, secret_name: str, secret: str, containers: List) -> None:
Owner

for a more intuitive function signature it would be good to pass a boolean was_deployed instead of the complete list of containers.

for a more intuitive function signature it would be good to pass a boolean `was_deployed` instead of the complete list of containers.
@ -892,3 +1026,3 @@
insert_secrets_from_conf(domain, app_config)
run_secret_hooks(domain, app_config)
exchange_secrets(app, instance_config, instance_apps)
# Pass 2: exchange secrets between apps, then generate any remaining missing secrets.
Owner

I really like the idea of splitting the secret insertion and secret exchange into two phases. I've never run into the case that I wanted to explicitly insert a secret first and the exchange it, therefore I never thought about this case.

I really like the idea of splitting the secret insertion and secret exchange into two phases. I've never run into the case that I wanted to explicitly insert a secret first and the exchange it, therefore I never thought about this case.
This pull request can be merged automatically.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u secret-sync:eCommons-secret-sync
git checkout eCommons-secret-sync
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: toolshed/alakazam#5
No description provided.