Skip to content

feat: single global secret - #123

Merged
cristinaponcela merged 8 commits into
mainfrom
feat/single-global-secret
Jul 6, 2026
Merged

feat: single global secret#123
cristinaponcela merged 8 commits into
mainfrom
feat/single-global-secret

Conversation

@cristinaponcela

@cristinaponcela cristinaponcela commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

This PR adds the proposal in #122.

It adds a flag 'shared' | 'unique', with default shared. This makes HTTP-hook secret placeholders now use marker mode: guest env vars get <random-marker>.<normalized_secret_name> instead of per-secret random placeholders.

The host replacement path was updated to recognize these structured references in headers, basic auth, and optional query params, resolve them back to the configured secret by identifier, and then apply the existing allowlist/update/delete behavior.

Unique GONDOLIN_SECRET_<random> placeholders remain available via secretPlaceholderMode: "unique", and docs/tests were updated accordingly.

@cristinaponcela
cristinaponcela requested a review from vegarsti June 8, 2026 13:47
@cristinaponcela cristinaponcela changed the title Feat/single global secret feat: single global secret Jun 8, 2026

@vegarsti vegarsti left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this makes a lot of sense, and the implementation is sound! Thank you and sorry for not reviewing this before

Comment thread host/src/http/hooks.ts Outdated
return [];
}

const byIdentifier = new Map(entries.map((entry) => [entry.identifier, entry]));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The clanker suggested this should be changed since custom-placeholder secrets also get a marker alias. collectMarkerSecretReferenceRanges() builds the marker identifier map from all secret entries, including entries with explicit custom placeholders

Not sure it's correct 🤔

  const byIdentifier = new Map(
    entries
      .filter(
        (entry) => entry.placeholder === `${context.marker}.${entry.identifier}`,
      )
      .map((entry) => [entry.identifier, entry]),
  );

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really good shout! Fixed in 0b3ca7e 🙏

Comment thread host/src/http/hooks.ts
name: string,
secret: SecretDefinition,
mode: SecretPlaceholderMode,
marker: string | undefined,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if marker is undefined here? I think we can get <undefined>.${identifier} on line 369 then? 🤔

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice nothing, because createHttpHooks() only calls resolveSecretPlaceholder() with mode === "shared" when it has already created a marker. But hardened the type to throw anyways, thanks!

@mitsuhiko

Copy link
Copy Markdown
Member

I think this is fine, but I don't think we should call the other mode legacy. Ideally we just call it shared and unique or something and we explain the differences.

@cristinaponcela
cristinaponcela merged commit 29fa74d into main Jul 6, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants