Skip to content

feat(linear): resolve API token via AgentCore Identity (Phase 2.0a)#2

Draft
isadeks wants to merge 1 commit into
feat/linear-processor-feedbackfrom
feat/agentcore-identity-api-key
Draft

feat(linear): resolve API token via AgentCore Identity (Phase 2.0a)#2
isadeks wants to merge 1 commit into
feat/linear-processor-feedbackfrom
feat/agentcore-identity-api-key

Conversation

@isadeks
Copy link
Copy Markdown
Owner

@isadeks isadeks commented May 15, 2026

Summary

Phase 2.0a of the Linear v2 plan. Stacked on PR aws-samples#87 (feat/linear-processor-feedback); this PR's base is set to that branch so the diff shows only the 2.0a changes. Once aws-samples#87 merges upstream, this will rebase onto main and open against aws-samples.

Migrates the agent runtime's Linear personal API token resolution from AWS Secrets Manager to AWS Bedrock AgentCore Identity. This is the "validate the Identity SDK" step before the bigger OAuth + Gateway cutover in Phase 2.0b.

Per Alain's guidance from the v1.1 review thread:

"Ideally yeah, you can try when exposing the server through agentcore gateway. you will setup an outbound auth for your server using agentcore identity. that identity can be (AC identity is like a wrapper around secrets manager) api key or oauth. start by using api key, if it works, switch to oauth."

Scope: agent runtime only

Lambdas (orchestrator + processor) intentionally keep using Secrets Manager. Reason: the Python bedrock_agentcore SDK has no Node.js equivalent — Lambda migration requires @aws-sdk/client-bedrock-agentcore raw API calls and folds into 2.0b's bigger refactor (where OAuth tokens replace API keys for all consumers in one cutover).

End-state of 2.0a:

  • Agent reads from AgentCore Identity ✓
  • Lambdas read from Secrets Manager (unchanged) ✓
  • Both point at the same underlying token value (admin runs agentcore add credential once and populates Linear API token in both stores)

What changed

agent/src/config.py::resolve_linear_api_token

  • Drops boto3 SecretsManager fetch + LINEAR_API_TOKEN_SECRET_ARN env var
  • Reads new env LINEAR_API_KEY_PROVIDER_NAME (provider name in the Identity vault, default: linear-api-key)
  • Calls IdentityClient.get_api_key() with the workload access token auto-injected into BedrockAgentCoreContext by AgentCore Runtime
  • Caches the resolved token in LINEAR_API_TOKEN env so downstream consumers stay unchanged: channel_mcp.py's \${LINEAR_API_TOKEN} placeholder in .mcp.json and linear_reactions.py's GraphQL Authorization header

Why imperative IdentityClient.get_api_key() instead of the @requires_api_key decorator: API keys don't need refresh. The decorator pattern shines for OAuth (refresh tokens, scopes, per-session binding) and is the right shape for 2.0b. For a static API key fetched once at agent startup, the imperative form keeps the MCP-config-with-placeholder model working unchanged.

Verified by reading the SDK's auth.py: the @requires_api_key decorator does exactly client.get_api_key(provider_name=..., agent_identity_token=BedrockAgentCoreContext.get_workload_access_token()). Inside AgentCore Runtime the context returns the auto-injected token; outside (Lambda, local dev) it returns None. Our imperative version matches that behaviour without the decorator's call-site rewrite.

Preserves PR aws-samples#87's nice-to-have improvements

  • ImportError graceful fallback adapted from boto3 to bedrock_agentcore — degrade with WARN, don't crash the agent
  • AccessDeniedException (likely missing IAM permission) and ResourceNotFoundException (provider name typo / not yet created) logged at ERROR severity to page someone, not WARN
  • Other ClientErrors (transient throttle, network) stay at WARN

cdk/src/stacks/agent.ts

On the AgentCore runtime:

  • Drops linearIntegration.apiTokenSecret.grantRead(runtime) and the LINEAR_API_TOKEN_SECRET_ARN env-var override
  • Adds LINEAR_API_KEY_PROVIDER_NAME env (hardcoded 'linear-api-key' for now)
  • Adds IAM for bedrock-agentcore:GetResourceApiKey + bedrock-agentcore:GetWorkloadAccessToken

Lambdas untouched. Verified at synth: only the AgentCore runtime's IAM policy and env vars changed.

Resource scope on the new IAM is * for now; the canonical AgentCore Identity ARN format isn't fully documented in public AWS docs as of 2026-05-15. Tighten in 2.0b when OAuth migration documents the resource shape.

docs/guides/LINEAR_SETUP_GUIDE.md

Adds Step 4.5 documenting the one-time admin command users run alongside the existing bgagent linear setup wizard:

agentcore add credential --type api-key --name linear-api-key
# (paste the same lin_api_… token when prompted)

Explains the dual-store setup and notes that 2.0b will retire the duplicate. Starlight mirror synced.

Tests

agent/tests/test_config.py::TestResolveLinearApiToken — 10 tests covering: cached env-var fast path; missing provider name; missing region; workload token absent (outside runtime); happy path with env-var side-effect; botocore errors swallowed; SDK returns None defensively; ImportError fallback; AccessDeniedException → ERROR severity; ResourceNotFoundException → ERROR severity.

542 agent / 1271 cdk / 196 cli — all green. Lint clean. Typecheck clean. CDK synth clean.

Phase plan context

2.0a  ← THIS PR — API key via AgentCore Identity (agent only)
2.0b  ← Linear OAuth + Gateway in one cutover (all consumers, retires Secrets Manager)
2.1   ← Agent Sessions UX (status pill, activities, retires reaction-spam)
2.2   ← AgentSessionEvent webhooks (@bgagent natural-language prompts)
2.3   ← HITL adapter via select activities (post Sam's #88 merge)

Reviewer notes

  • Smoke not run yet. The MCP placeholder, GraphQL header, and run.sh env-var pass-through are all unchanged — only the source of LINEAR_API_TOKEN changed. Unit tests cover the new code path with realistic SDK mocks. Will deploy + smoke before requesting upstream review.
  • Provider name hardcoded as 'linear-api-key'. Happy to parametrize via CDK context if reviewer prefers — opted for the simple shape since there's one deployment.
  • Promotion to upstream: when feat(linear): v1.1 polish — pre-container feedback, state-on-start, sweep, nits aws-samples/sample-autonomous-cloud-coding-agents#87 merges, rebase this onto aws-samples/main and open the cross-fork PR against main.

Migrates the agent runtime's Linear personal API token resolution from
AWS Secrets Manager to AWS Bedrock AgentCore Identity. This is the
"validate Identity SDK" step of the v2 plan; Phase 2.0b will swap the
API key for OAuth and converge Linear MCP onto AgentCore Gateway in
one cutover.

Per Alain's guidance: "start by using api key, if it works, switch to
oauth. you will setup an outbound auth for your server using agentcore
identity. that identity can be (AC identity is like a wrapper around
secrets manager) api key or oauth."

## Scope: agent runtime only

Lambdas (orchestrator + processor) intentionally keep using Secrets
Manager via the existing `LinearApiTokenSecret` for now. The Python
`bedrock_agentcore` SDK has no Node.js equivalent — Lambda migration
requires `@aws-sdk/client-bedrock-agentcore` raw API calls and folds
into 2.0b's bigger refactor. End-state of 2.0a: agent reads from
Identity, Lambdas read from Secrets Manager, both pointing at the same
underlying token value (admin populates both).

## What changed

`agent/src/config.py::resolve_linear_api_token`:

  - Drops boto3 SecretsManager fetch + `LINEAR_API_TOKEN_SECRET_ARN` env.
  - Reads new env `LINEAR_API_KEY_PROVIDER_NAME` (provider name in
    Identity vault).
  - Calls `IdentityClient.get_api_key()` with the workload access token
    auto-injected into `BedrockAgentCoreContext` by AgentCore Runtime
    (verified by reading the SDK's `auth.py` decorator implementation —
    no manual workload-identity mint needed inside the runtime).
  - Caches the resolved token in `LINEAR_API_TOKEN` so downstream
    consumers stay unchanged: `channel_mcp.py`'s `${LINEAR_API_TOKEN}`
    placeholder in `.mcp.json` and `linear_reactions.py`'s GraphQL
    Authorization header.

Preserves PR aws-samples#87's nice-to-have improvements:

  - `ImportError` graceful fallback (now for `bedrock_agentcore` instead
    of `boto3`) — degrade with WARN, don't crash the agent.
  - `AccessDeniedException` and `ResourceNotFoundException` logged at
    ERROR severity (persistent IAM/config bugs that should page).
    Other ClientErrors stay at WARN (transient throttle/network).

`agent/pyproject.toml`: adds `bedrock-agentcore==1.9.1` dep.

`cdk/src/stacks/agent.ts`:

  - On the AgentCore runtime: drops `linearIntegration.apiTokenSecret.
    grantRead(runtime)` and the `LINEAR_API_TOKEN_SECRET_ARN` env-var
    override. Adds `LINEAR_API_KEY_PROVIDER_NAME` env (hardcoded
    `'linear-api-key'` for now; can parametrize later via context if
    multi-environment naming is needed) and IAM permissions for
    `bedrock-agentcore:GetResourceApiKey` and
    `bedrock-agentcore:GetWorkloadAccessToken`.
  - Lambdas (orchestrator + processor) untouched — they still grant on
    the Linear secret and read from Secrets Manager.
  - Resource scope on the new IAM is `*` for now; AgentCore Identity ARN
    format isn't fully standardized in public docs as of 2026-05-15.
    Tighten in 2.0b when OAuth migration documents the canonical
    resource shape.

`docs/guides/LINEAR_SETUP_GUIDE.md`: adds Step 4.5 documenting the
one-time `agentcore add credential --type api-key --name linear-api-key`
admin command users must run alongside the existing `bgagent linear
setup` wizard. Notes that Lambdas keep Secrets Manager temporarily and
2.0b will retire the dual-store setup. Starlight mirror synced.

## Tests

`agent/tests/test_config.py::TestResolveLinearApiToken` — 10 tests
covering: cached env var fast-path; missing provider name; missing
region; workload token absent (outside runtime); happy path with
env-var side-effect; botocore error swallowed with WARN; SDK returns
None defensively; ImportError fallback; AccessDeniedException → ERROR
severity; ResourceNotFoundException → ERROR severity.

542 agent / 1271 cdk / 196 cli, all green. Lint + typecheck clean.
CDK synth clean.

## Migration notes for reviewer

`bedrock_agentcore` SDK confirmed working in our runtime image (verified
in `node_modules` post-install). The `BedrockAgentCoreContext` workload
token auto-injection is documented behaviour for code running inside
AgentCore Runtime — verified by reading the SDK's `@requires_api_key`
decorator implementation, which uses the same context lookup we use
here.

Stacked on PR aws-samples#87 (`feat/linear-processor-feedback`). Will conflict on
`config.py` and `test_config.py` if aws-samples#87 needs further rework before
merge — happy to rebase.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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