Skip to content

feat: opt-in local connector execution with JIT secret hydration - #46

Draft
Johnny Schmidt (johnny-schmidt) wants to merge 4 commits into
mainfrom
feat/local-execution-jit-secret-hydration
Draft

Johnny Schmidt (johnny-schmidt) wants to merge 4 commits into
mainfrom
feat/local-execution-jit-secret-hydration

Conversation

@johnny-schmidt

Copy link
Copy Markdown

Overview

Adds an opt-in local execution path to airbyte-agent connectors execute. Hosted execution stays the zero-config default and is unchanged. In local mode the CLI:

  1. POST .../execute/prepare (same body as hosted /execute, incl. intent) → unhydrated execute bundle
  2. hydrates secret_coordinate:: values from a customer-owned AWS Secrets Manager in memory
  3. performs the connector HTTP request from the CLI process over an isolated hardened transport
airbyte-agent connectors execute --execution-mode local --json @request.json
# or: AIRBYTE_EXECUTION_MODE=local, optionally --aws-profile / --aws-region (post `aws sso login`)

What's here

Area Change
cmd/, internal/config Global --execution-mode/--aws-profile/--aws-region flags + deterministic precedence; SDK-compatible AWS_SECRET_MANAGER_* env set
internal/secrets (+/aws) Provider-neutral hydration walker; AWS Secrets Manager provider (strict SecretString, cached-SSO login remediation, redacted typed errors)
internal/localexec Native Go bundle→request-plan compiler (OpenAPI-3 + x-airbyte-*, restricted JSONPath), auth mapping, HTTPS-only transport, response shaping, orchestrating executor
internal/resources connectors execute branches on runtime mode; fail-closed (no hosted fallback), validate-before-hydrate, bundle removed from output
docs/skills README, CONTEXT, AGENTS, SKILL + connectors-execute reference (IAM least-privilege, precedence, fail-closed model)

Security properties

  • No secret-bearing flags; connector-origin traffic never carries Airbyte bearer/org headers (separate transport, auth/cookie stripped on cross-origin redirect)
  • Hydrated secrets are invocation-local, never persisted or cached across calls
  • Static validation (unsupported action / refreshable OAuth / download / advanced JSONPath) runs before any AWS/network call
  • Every local failure is structured, redacted, terminal — never falls back to hosted

Verification

gofmt clean · go vet ./... · go build -mod=readonly ./... · go test ./... · -race on localexec/secrets/resources · go generate idempotent · go 1.22.0 directive preserved.

Built with a locally-installed go1.27.0 (GOTOOLCHAIN=local) — go was not on PATH in the dev environment.

⚠️ Review-critical deviations (forced by an offline dev environment)

Draft because these need reconciliation before merge/release:

  1. api/app_public.json was hand-edited, NOT synced from the pinned Sonar revision (ff7c970…) — Sonar was unreachable. ConnectorExecuteResponse got optional bundle/warning and non-required result; extracted_gen.go regenerated. Reconcile against a real upstream sync.
  2. Connector-request parity fixtures are self-consistent, not byte-diffed against live Sonar output. Validate against real connector definitions.
  3. Live-AWS acceptance is covered only by injected-fake unit tests. The manual matrix (real SSO profile + real Secrets Manager, SSO expiry remediation) still needs a run.
  4. AWS SDK v2 pinned to Go-1.22-compatible versions (config v1.29.14, etc.). go mod tidy bumps the go directive to 1.24 — don't run it without intent.

🤖 Generated with Claude Code

Add an opt-in local execution path to `connectors execute`. Hosted
execution remains the zero-config default. In local mode the CLI fetches
an unhydrated execute bundle from Sonar via `POST .../execute/prepare`,
hydrates `secret_coordinate::` values from a customer-owned AWS Secrets
Manager in memory, and performs the connector HTTP request from the CLI
process over an isolated hardened transport.

- Global root flags --execution-mode/--aws-profile/--aws-region with
  deterministic precedence; SDK-compatible AWS_SECRET_MANAGER_* env set.
- internal/secrets + internal/secrets/aws: provider-neutral hydration
  walker and AWS Secrets Manager provider (strict SecretString, cached-SSO
  login remediation, redacted typed errors).
- internal/localexec: native Go compiler from bundle YAML to an immutable
  request plan (OpenAPI-3 + x-airbyte-* extensions, restricted JSONPath),
  auth mapping, isolated HTTPS-only transport (no Airbyte headers, redirect
  /body/timeout bounds, safe-method-only retries), and response shaping.
- connectors execute branches on runtime mode; fail-closed (no hosted
  fallback), validation before hydration, bundle removed from output.
- Stable local error taxonomy mapped to exit codes; docs + skill guidance.

Fail-closed by construction: no secret-bearing flags, connector-origin
traffic never carries Airbyte credentials, hydrated secrets are
invocation-local and never persisted.

AWS SDK v2 pinned to Go-1.22-compatible versions; yaml.v3 added.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nvelope

The prepare endpoint serializes the backend's shared ConnectorExecuteResponse,
which always includes `result` (null on the direct/local path) and
`context_store_bundle` (added for context-store local execution). The strict
DecodeEnvelope (DisallowUnknownFields) rejected both as unknown fields, failing
every real local execution with "envelope is not valid JSON". Model both as
ignored fields so the decoder accepts the real response while still rejecting
genuinely unexpected fields.
…ions

Real connector definitions (e.g. Stripe) emit a boolean `required: true` on
individual property schemas, alongside the object-level `required: [names]`
list. Unmarshaling a bool into Schema.Required ([]string) failed the whole
parse with "definition_yaml is not valid YAML". Decode `required` through a
tolerant type that yields the name list for a sequence and an empty list for
any non-sequence value.
Check the discarded error returns golangci-lint's errcheck flags: the
httptest w.Write calls in executor_test.go and the assertType helper returns
in the AWS provider tests (the *secrets.Error return was dropped at soft-miss
call sites). Bump skills/airbyte-agent/SKILL.md to v0.1.3 for the local-
execution docs this PR adds, satisfying the skill-version-bump gate.

Claude-Session: https://claude.ai/code/session_01Hyh5zmKZ9p8Z5HmykM3NZU
@johnny-schmidt
Johnny Schmidt (johnny-schmidt) force-pushed the feat/local-execution-jit-secret-hydration branch from 66b4898 to 3094cc8 Compare August 28, 2026 20:53
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.

1 participant