Skip to content

feat(config): add --app-privatekey (in-memory PEM) flag (CXP-585)#175

Open
c1-squire-dev[bot] wants to merge 2 commits into
mainfrom
john.allers/CXP-585/baton-github-app-privatekey-flag
Open

feat(config): add --app-privatekey (in-memory PEM) flag (CXP-585)#175
c1-squire-dev[bot] wants to merge 2 commits into
mainfrom
john.allers/CXP-585/baton-github-app-privatekey-flag

Conversation

@c1-squire-dev

@c1-squire-dev c1-squire-dev Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements CXP-585: add a new --app-privatekey flag to baton-github that accepts the raw PEM contents of the GitHub App private key as a string, for in-memory / secret-based credentials.

Today the connector can only load a GitHub App private key from disk via --app-privatekey-path. This change is additive and does not change the existing path-based behavior.

Behavior

  • New flag --app-privatekey (env $BATON_APP_PRIVATEKEY), marked secret.
  • Precedence: when both are set, --app-privatekey wins; otherwise the connector falls back to --app-privatekey-path.
  • Providing either one satisfies the "app private key required" check.
  • The PEM is parsed exactly as before (PKCS#8 / PKCS#1, same loadPrivateKeyFromString path). The key is never logged.

Implementation notes

  • pkg/config/config.go: added appPrivateKey StringField (secret); removed the individual WithRequired(true) on appPrivateKeyPath and added both fields to the GitHub App field group. The "at least one" requirement is enforced in the connector's GitHub App constructor rather than as a framework constraint, because field-relationship constraints are evaluated globally across auth methods and would otherwise break the personal-access-token auth path.
  • Regenerated pkg/config/conf.gen.go (via go generate ./pkg/config) and config_schema.json (via connector config) — not hand-edited.
  • pkg/connector/connector.go: added appPrivateKeyPEM() precedence helper, used in newWithGithubApp for both the initial JWT and the JWT refresher.
  • Docs: README.md flag list + docs/connector.mdx Kubernetes secret example.
  • Added pkg/connector/app_privatekey_test.go covering precedence, single-source, fallback, and neither-set cases.

Verification

  • go build ./...
  • go vet ./...
  • go test ./... ✅ (new TestAppPrivateKeyPEM passes)
  • golangci-lint run ./pkg/... — only the pre-existing G115 finding in repository.go (untouched by this PR).

🤖 Generated with Claude Code


🏰 Squire environment: merry-frog-90199
Task: a3d48baf-d5cb-470a-a99e-3ac377ba4d5e

Add a new `--app-privatekey` flag that accepts the raw PEM contents of the
GitHub App private key as a string, for in-memory / secret-based credentials.
This complements the existing `--app-privatekey-path` (read from disk).

When both are set, `--app-privatekey` takes precedence; otherwise the
connector falls back to `--app-privatekey-path`. Providing either one
satisfies the "app private key required" check, which is now enforced in the
GitHub App constructor (a framework-level constraint can't be scoped to a
single auth-method group). The new flag is marked secret and the key is
never logged.

- pkg/config/config.go: add appPrivateKey StringField (secret), drop the
  individual required rule on appPrivateKeyPath, add both to the GitHub App
  field group. Regenerated conf.gen.go and config_schema.json.
- pkg/connector/connector.go: add appPrivateKeyPEM() precedence helper and
  use it in newWithGithubApp for the JWT token and the JWT refresher.
- README.md / docs/connector.mdx: document the new flag.
- pkg/connector/app_privatekey_test.go: cover the precedence/fallback/error
  cases.

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
@c1-squire-dev c1-squire-dev Bot requested a review from a team June 15, 2026 13:52
@linear-code

linear-code Bot commented Jun 15, 2026

Copy link
Copy Markdown

CXP-585

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Connector PR Review: feat(config): add --app-privatekey (in-memory PEM) flag (CXP-585)

Blocking Issues: 0 | Suggestions: 0 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base 176236539eb4.
Review mode: incremental since 31b1d30
View review run

Review Summary

The full PR diff was scanned for security and correctness. The only new commit since the last review adds pkg/config/config_validation_test.go, which locks in that the PAT auth method validates with just a token and documents why the at-least-one app private key requirement lives in the connector constructor (appPrivateKeyPEM) rather than as a global framework constraint. The tests match the shipped behavior in config.go and connector.go; no new issues found.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

None.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No blocking issues found.

@laurenleach laurenleach left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The "at least one" requirement is enforced in the connector's GitHub App constructor rather than as a framework constraint, because field-relationship constraints are evaluated globally across auth methods and would otherwise break the personal-access-token auth path.

we filter out fields not in the field group, so we should be able to use the field constraint of "at least one" for app-privatekey-path/app-privatekey

…s connector-local

Adds regression coverage for CXP-585 PR feedback questioning whether the
"at least one of --app-privatekey / --app-privatekey-path" requirement could
be expressed as a framework field.FieldsAtLeastOneUsed constraint instead of
connector-local validation.

Investigation shows it cannot on the SDK version this connector vendors
(v0.14.7; logic is unchanged through v0.17.0): field.Validate filters the
field *presence* map by the selected auth-method group, but validateConstraints
evaluates every Configuration constraint globally with no notion of field
groups, and SchemaFieldGroup cannot carry group-scoped constraints. A global
AtLeastOne(app-privatekey-path, app-privatekey) therefore fires whenever
neither key is set — including under the personal-access-token auth method and
the default no-auth-method case — which would reject the common
`baton-github --token=...` invocation.

- TestConfigValidationAuthMethods: locks in that PAT/default auth validates
  with only a token, and that both GitHub App key sources validate.
- TestFrameworkAtLeastOneConstraintBreaksPATAuth: builds a config mirroring the
  real one plus that constraint and asserts it breaks PAT auth, codifying the
  design rationale. It will fail (prompting a move to the framework) if a future
  SDK makes constraints group-aware.

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No blocking issues found.

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