Skip to content

feat(expressions): add repoCredentials() expression function - #6558

Draft
jsbroks wants to merge 2 commits into
mainfrom
feat/repo-credentials-expr-fn
Draft

feat(expressions): add repoCredentials() expression function#6558
jsbroks wants to merge 2 commits into
mainfrom
feat/repo-credentials-expr-fn

Conversation

@jsbroks

@jsbroks jsbroks commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Description

Closes #6549

Adds a repoCredentials() expression function that resolves repository credentials by repo URL and credential type (git, helm, image), returning them as a map[string]string. It is a thin entry point into the same credentials database used by built-in promotion steps like git-clone.

Unlike secret(), which returns the raw Data of a Secret selected by name, repoCredentials() returns the resolved credentials — not the raw contents of the underlying Secret. This means it transparently handles credential schemes that yield narrowly-scoped, short-lived credentials (e.g. a GitHub App installation token minted from an app ID + private key, or a cloud provider's ambient / Pod-identity credentials), which is exactly what custom and generic steps (e.g. http calling a provider API) need but previously had no way to obtain.

Behavior

  • Signature: repoCredentials(repoURL, type) where type is one of git,
    helm, or image. The type is required because credentials are indexed by
    type and the same URL may resolve differently per type (URL normalization also
    differs per type).
  • When credentials are found, it always returns the fixed set of keys
    username, password, sshPrivateKey (empty string when unset), so
    expression authors can rely on a predictable shape regardless of provider.
    API keys / personal access tokens / minted tokens are surfaced via password.
  • When no credentials are found, it returns an empty map (mirroring secret()).

Implementation

  • New RepoCredentials() option and getRepoCredentials() implementation in
    pkg/expressions/function, wired into DataOperations() (which now takes a
    credentials.Database).
  • StepEvaluator now carries the credentials database and threads it through
    Vars / ShouldSkip / Config; LocalOrchestrator passes the DB it already
    receives.
  • Caching mirrors secret() (per-step cache, distinct RepoCredentials
    key prefix).

Reviewer notes

  • Contexts without a credentials database — Stage verification argument
    evaluation, the Argo CD selector, and the indexer — register the function but
    return a clear "not available in this context" error if it is invoked. Fully
    wiring a credentials DB into the Stage controller was intentionally left out to
    limit blast radius; happy to follow up if we want it there too.
  • Custom / pod-based steps are the primary intended consumer (per the
    discussion on expression function for repo credential lookup by url #6549). This PR wires the function into the OSS StepEvaluator
    config-evaluation path; the Enterprise pod-based executor's config-evaluation
    path should be confirmed to flow through the same wiring.
  • Security consideration for discussion: because the function materializes a
    (possibly minted) token into the expression environment, that token can flow
    into a step's outputs, logs, or committed files. Worth deciding whether any
    guardrails are wanted here.

Checklist

Eligibility

  • Linked to an existing issue with no blocking labels.
  • Changes documentation only.
  • Changes ten lines or fewer.

Quality

  • Adds or updates corresponding tests.
  • Adds or updates corresponding documentation.

AI Use Disclosure

This PR was written:

  • By a human without AI assistance.
  • By a human with AI assistance. A human has reviewed every line prior to opening the PR.
  • By an AI with human supervision. A human has reviewed every line prior to opening the PR.
  • Entirely by an AI. No human has reviewed this prior to opening the PR.

Sign-Off

All commits:

  • Are signed off by their author (git commit -s) (required)
  • Are cryptographically signed (git commit -S) (encouraged)

@netlify

netlify Bot commented Jul 6, 2026

Copy link
Copy Markdown

Deploy Preview for docs-kargo-io ready!

Name Link
🔨 Latest commit 6ecfff2
🔍 Latest deploy log https://app.netlify.com/projects/docs-kargo-io/deploys/6a4fa499bc6db70008ce3905
😎 Deploy Preview https://deploy-preview-6558.docs.kargo.io
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@kargo-governance-bot kargo-governance-bot Bot added area/controller Affects the (main) controller area/security Has security implications and needs to be handled with great caution kind/enhancement An entirely new feature needs/priority Priority has not yet been determined; a good signal that maintainers aren't fully committed labels Jul 6, 2026
@codecov

codecov Bot commented Jul 6, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.07463% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 58.81%. Comparing base (de4b5e3) to head (6ecfff2).
⚠️ Report is 18 commits behind head on main.

Files with missing lines Patch % Lines
pkg/expressions/function/functions.go 84.90% 8 Missing ⚠️
cmd/controlplane/controller.go 0.00% 1 Missing ⚠️
pkg/controller/stages/regular_stages.go 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6558      +/-   ##
==========================================
+ Coverage   58.68%   58.81%   +0.12%     
==========================================
  Files         506      506              
  Lines       42846    42985     +139     
==========================================
+ Hits        25146    25280     +134     
- Misses      16157    16166       +9     
+ Partials     1543     1539       -4     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread pkg/expressions/function/functions.go Outdated
Comment thread pkg/controller/stages/regular_stages.go Outdated
@jsbroks jsbroks closed this Jul 8, 2026
@jsbroks jsbroks reopened this Jul 9, 2026
Justin Brooks and others added 2 commits July 9, 2026 09:39
Add a `repoCredentials()` expression function that resolves repository
credentials by repo URL and credential type (`git`, `helm`, `image`)
through the same credentials database used by built-in promotion steps.

Unlike `secret()`, which returns the raw `Data` of a Secret selected by
name, `repoCredentials()` returns the *resolved* credentials -- e.g. a
minted, short-lived GitHub App installation token -- so custom and generic
steps (such as `http`) can obtain usable credentials for repositories they
need to access, instead of only the raw material stored in the Secret.

The function is wired into the promotion StepEvaluator, which now carries
the credentials database. When credentials are found it always returns a
fixed, predictable set of keys (`username`, `password`, `sshPrivateKey`);
when none are found it returns an empty map, mirroring `secret()`.
Contexts that do not wire a credentials database (Stage verification
argument evaluation, the Argo CD selector, and the indexer) register the
function but return a clear error if it is invoked.

Signed-off-by: Justin Brooks <justin.brooks@akuity.io>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Justin Brooks <justin.brooks@akuity.io>
…conciler

Signed-off-by: Justin Brooks <justin.brooks@akuity.io>
@jsbroks
jsbroks force-pushed the feat/repo-credentials-expr-fn branch from 6303c0a to 6ecfff2 Compare July 9, 2026 13:39
@jsbroks
jsbroks requested a review from krancour July 9, 2026 14:38
Comment on lines +500 to +501
If no matching credentials are found, an object with all fields empty is
returned.

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.

This might not be the optimal behavior. It's common to use optional chaining and nil-coalescing in expressions, so returning nil is probably a more useful signal when no credentials are found.

// authors can rely on a predictable shape regardless of credential type
// or provider. When no credentials are found, a zero-value struct (all
// fields empty) is returned.
var result credentials.Credentials

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/controller Affects the (main) controller area/security Has security implications and needs to be handled with great caution kind/enhancement An entirely new feature needs/priority Priority has not yet been determined; a good signal that maintainers aren't fully committed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

expression function for repo credential lookup by url

2 participants