2026-06-26 16:07:23 -04:00
|
|
|
|
import * as cdk from "aws-cdk-lib";
|
|
|
|
|
|
import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager";
|
|
|
|
|
|
import * as ssm from "aws-cdk-lib/aws-ssm";
|
|
|
|
|
|
import { Construct } from "constructs";
|
|
|
|
|
|
import { EnvName } from "../config";
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Config / secret "shells" for the boot hook (`deploy/seahaven/fetch-config.sh`).
|
|
|
|
|
|
*
|
|
|
|
|
|
* The naming contract (source of truth: the T9 env/secret/config inventory + the
|
|
|
|
|
|
* fetch-config header) is LITERAL env-var names as the last path segment:
|
|
|
|
|
|
*
|
|
|
|
|
|
* Secrets open-swe-<env>/<ENV_VAR_NAME> (AWS Secrets Manager)
|
|
|
|
|
|
* Config /open-swe-<env>/<ENV_VAR_NAME> (AWS SSM Parameter Store, FLAT)
|
|
|
|
|
|
*
|
|
|
|
|
|
* fetch-config reads secrets with `batch-get-secret-value --filters
|
|
|
|
|
|
* Key=name,Values=open-swe-<env>/` and config with `get-parameters-by-path
|
|
|
|
|
|
* --path /open-swe-<env>/` (NON-recursive), then strips the prefix so the last
|
|
|
|
|
|
* segment IS the exported variable name. So these resources MUST carry the
|
|
|
|
|
|
* UPPER_SNAKE env-var name verbatim — which is why both resource types are
|
|
|
|
|
|
* exempted from the kebab-naming Aspect (see aspects/kebab-naming-aspect.ts).
|
|
|
|
|
|
*
|
|
|
|
|
|
* Three buckets:
|
|
|
|
|
|
*
|
|
|
|
|
|
* 1. SECRETS_SHELLS — the 29 secrets. Created as value-LESS shells (an L1
|
|
|
|
|
|
* `CfnSecret` with NEITHER `secretString` NOR `generateSecretString`, which
|
|
|
|
|
|
* CloudFormation creates as an empty secret with no version). The real value
|
|
|
|
|
|
* is set out-of-band via `deploy/seahaven/put-config.sh` (put-secret-value)
|
|
|
|
|
|
* BEFORE the box boots. Because CDK never owns the value, a later
|
|
|
|
|
|
* `cdk deploy` can never clobber the operator-set value. AWS-managed key
|
|
|
|
|
|
* (alias/aws/secretsmanager) — no CMK, matching the instance role which
|
|
|
|
|
|
* deliberately omits kms:Decrypt.
|
|
|
|
|
|
*
|
|
|
|
|
|
* 2. IAC_MANAGED_SSM — stable / derivable config. Real values are owned here in
|
|
|
|
|
|
* IaC (one StringParameter each) so they are reproducible and reviewed.
|
|
|
|
|
|
*
|
|
|
|
|
|
* 3. Out-of-band SSM (NOT created here) — operationally-variable or
|
|
|
|
|
|
* env-specific-unknown config (e.g. DEFAULT_SANDBOX_SNAPSHOT_ID, which
|
|
|
|
|
|
* changes on every snapshot rebuild and would be clobbered by a deploy if it
|
|
|
|
|
|
* were CDK-managed; GitHub App ids; Slack ids; LangSmith tenant/urls). These
|
|
|
|
|
|
* are listed in OUT_OF_BAND_SSM purely for documentation and are set by
|
|
|
|
|
|
* `put-config.sh`, never by CDK.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/** The 29 Secrets Manager secret VAR names (T9 inventory SECRETS table). */
|
|
|
|
|
|
export const SECRET_VARS: readonly string[] = [
|
|
|
|
|
|
"ANTHROPIC_API_KEY",
|
|
|
|
|
|
"CORRIDOR_API_TOKEN",
|
|
|
|
|
|
"CORRIDOR_MCP_TOKEN",
|
|
|
|
|
|
"CORRIDOR_TOKEN",
|
|
|
|
|
|
"DASHBOARD_JWT_SECRET",
|
|
|
|
|
|
"DAYTONA_API_KEY",
|
|
|
|
|
|
"EXA_API_KEY",
|
|
|
|
|
|
"FIREWORKS_API_KEY",
|
|
|
|
|
|
"GITHUB_APP_CLIENT_SECRET",
|
|
|
|
|
|
"GITHUB_APP_PRIVATE_KEY",
|
|
|
|
|
|
"GITHUB_PAT",
|
|
|
|
|
|
"GITHUB_WEBHOOK_SECRET",
|
|
|
|
|
|
"JUDGE_ANTHROPIC_API_KEY",
|
|
|
|
|
|
"LANGSMITH_API_KEY",
|
|
|
|
|
|
"LANGSMITH_API_KEY_PROD",
|
|
|
|
|
|
"LANGCHAIN_API_KEY",
|
|
|
|
|
|
"LINEAR_API_KEY",
|
|
|
|
|
|
"LINEAR_WEBHOOK_SECRET",
|
|
|
|
|
|
"RUNLOOP_API_KEY",
|
|
|
|
|
|
"SLACK_BOT_TOKEN",
|
|
|
|
|
|
"SLACK_CLIENT_SECRET",
|
|
|
|
|
|
"SLACK_SIGNING_SECRET",
|
|
|
|
|
|
"TOKEN_ENCRYPTION_KEY",
|
|
|
|
|
|
"USER_ID_API_KEY_MAP",
|
|
|
|
|
|
"X_SERVICE_AUTH_JWT_SECRET",
|
|
|
|
|
|
] as const;
|
feat: migrate model providers to Bedrock (Claude) + Fireworks (everything else) (#62)
* feat: switch model providers to AWS Bedrock (Claude) and Fireworks (non-Claude)
Migrate off direct provider APIs: AWS Bedrock for Anthropic/Claude via the
cross-region inference profile us.anthropic.claude-opus-4-8, Fireworks AI for
all non-Claude models. Drop OpenAI (gpt-5.5) and Google (gemini-3.5-flash)
entirely. DEFAULT_MODEL_ID is now Bedrock Claude; all Fireworks models stay
freely selectable for the agent and reviewer graphs and via team/profile
defaults.
- pyproject: add langchain-aws (ChatBedrockConverse + boto3)
- options.py: Bedrock Claude entry + default; remove openai/google entries
- model.py: bedrock_converse provider_model_kwargs (effort -> thinking budget),
region pin in make_model, bedrock<->fireworks fallback pairing, AWS_REGION/
FIREWORKS_API_KEY local-dev validation
- server.py: provider-aware fallback kwargs build
- sanitize_thinking_blocks: also sanitize ChatBedrockConverse thinking blocks
- model_fallback: treat transient botocore ClientError codes as fallback-worthy
- eval_jobs: repoint hardcoded eval model id to Bedrock Claude
- tests: repoint dropped model ids; drop obsolete google test module
* fix(bedrock): use adaptive thinking + output_config.effort for Opus 4.8
The handoff spec wired Bedrock Converse thinking as
{type: enabled, budget_tokens: N}, but Opus 4.7+ rejects that with a
ValidationException: thinking.type "enabled" is not supported; it requires
thinking.type "adaptive" plus output_config.effort. Verified by live invoke
against us.anthropic.claude-opus-4-8 (account 328440206208, us-east-1):
the enabled+budget shape 400s, adaptive+effort returns normally.
Map profile effort to additional_model_request_fields:
{thinking: {type: adaptive, display: summarized},
output_config: {effort: <low|medium|high|xhigh|max>}}
reusing anthropic_thinking_for/anthropic_effort_for. Update the two
subagent-model tests asserting the old shape.
* fix(deploy): seed Bedrock/Fireworks models, not the dropped anthropic:/openai: ids
Model selection is store-driven, so seed_store.sh's team_settings/default seed is
what runs in prod. It still seeded the removed providers, which would fail at runtime
after the migration:
- agent/builder: anthropic:claude-opus-4-8 -> bedrock_converse:us.anthropic.claude-opus-4-8
- reviewer: openai:gpt-5.5 (dropped) -> bedrock_converse:us.anthropic.claude-opus-4-8
(set SEED_REVIEWER_MODEL to a Fireworks model for a cross-family reviewer)
- fetch-config REQUIRED_PROVIDER_KEYS default ANTHROPIC_API_KEY,OPENAI_API_KEY ->
FIREWORKS_API_KEY (Bedrock auths via host IAM role; dropping the old keys would
otherwise fail-fast at boot)
- docs (DEPLOYMENT/ROTATION/put-config) updated to match.
Surfaced by the cross-family review + verified against deploy/.
* fix(bedrock): security-review NITs — region resolution, error sanitization, reasoning-block strip
From /sh-security-review (all confirmed-low):
- model.py: resolve region from AWS_REGION OR AWS_DEFAULT_REGION (matches
validate_local_dev_llm_config) so the validated region is the one actually used.
- model_fallback.py: sanitize Bedrock AccessDenied/ResourceNotFound errors to the
error code only, so the role ARN + account id in the raw botocore message never
reach logs or the user channel (CWE-209).
- sanitize_thinking_blocks.py: also strip empty Bedrock reasoning_content blocks
(Converse emits reasoning_content, not thinking) so the middleware is not a no-op
on Bedrock; + unit tests. (Empty blocks replay fine today; defensive.)
* deploy(bedrock): grant instance-role Bedrock invoke + repoint LLM_MODEL_ID / eval model ids
Deployment-readiness for the Bedrock migration (PR #62):
- instance-role.ts: least-privilege bedrock:InvokeModel[WithResponseStream] on the
us.anthropic.claude-opus-4-8 inference-profile ARN + the foundation-model ARN in
each routed region (us-east-1/2, us-west-2). The model runs in the server process
on the box, so the EC2 instance role is the principal. Simulator-verified (allowed
for opus-4-8, implicitDeny for other models) and synth-verified. Passed the
mandatory GPT-4.1 IAM cross-review (no blockers, least-privilege confirmed).
- config-store.ts: IaC SSM LLM_MODEL_ID anthropic:claude-opus-4-8 ->
bedrock_converse:us.anthropic.claude-opus-4-8. This SSM value overrides
seed_store.sh's default via pick precedence, so the seed-script fix alone was
insufficient — both sources now point at the supported Bedrock id.
- infra/README.md + evals/reviewer/config.toml: repoint stale anthropic:/google_genai:
ids to the Bedrock id (config.toml's model_id was an active, now-broken value).
AWS_REGION is already wired via user-data.sh (IMDS -> boot.env), so no change needed there.
* chore(secrets): drop OPENAI/GOOGLE/GROQ key shells (revoked, providers removed)
Those three providers were dropped in the Bedrock/Fireworks migration and their keys
revoked; the live Secrets Manager objects (open-swe-{dev,prod}/{OPENAI,GOOGLE,GROQ}_API_KEY)
were deleted (7-day recovery). Remove them from the IaC so a future cdk deploy does not
recreate the shells, and from fetch-config's mirror array so boot stops requesting them:
- config-store.ts SECRET_VARS + descriptions (28 -> 25 shells)
- fetch-config.sh SECRET_VARS array (kept in lockstep)
- put-config.sh: drop the put_secret lines; ANTHROPIC_API_KEY re-labelled optional
(eval judge only — Bedrock builder/reviewer auth via the host IAM role).
REQUIRED_PROVIDER_KEYS is not set in SSM, so it uses the FIREWORKS_API_KEY default.
2026-06-29 15:57:19 -04:00
|
|
|
|
// 25 secret shells (OPENAI_API_KEY / GOOGLE_API_KEY / GROQ_API_KEY removed in the
|
|
|
|
|
|
// Bedrock/Fireworks migration — those providers are dropped from SUPPORTED_MODELS and
|
|
|
|
|
|
// their keys revoked + secret objects deleted). The T9 inventory header said "29" vs
|
|
|
|
|
|
// 27 enumerated; reconciled
|
2026-06-26 16:07:23 -04:00
|
|
|
|
// (Adam confirm 2026-06-26): USER_ID_API_KEY_MAP (maps user ids -> API keys; flagged
|
|
|
|
|
|
// sensitive by the T5 security review) is a SECRET and is included here.
|
|
|
|
|
|
// JUDGE_ANTHROPIC_BASE_URL is a URL (non-sensitive config, eval-only) -> SSM/default,
|
|
|
|
|
|
// NOT a secret. So the inventory's "29" was effectively a miscount.
|
|
|
|
|
|
|
|
|
|
|
|
/** Short, value-free descriptions for the secret shells (no secret material). */
|
|
|
|
|
|
const SECRET_DESCRIPTIONS: Record<string, string> = {
|
|
|
|
|
|
ANTHROPIC_API_KEY: "Claude LLM API key (primary builder provider).",
|
|
|
|
|
|
CORRIDOR_API_TOKEN: "Corridor MCP token (optional).",
|
|
|
|
|
|
CORRIDOR_MCP_TOKEN: "Corridor MCP token alt name (optional).",
|
|
|
|
|
|
CORRIDOR_TOKEN: "Corridor MCP token alt name (optional).",
|
|
|
|
|
|
DASHBOARD_JWT_SECRET: "JWT signing secret for dashboard session cookies (REQUIRED).",
|
|
|
|
|
|
DAYTONA_API_KEY: "Daytona sandbox key (only if SANDBOX_TYPE=daytona).",
|
|
|
|
|
|
EXA_API_KEY: "Exa web-search key (optional).",
|
|
|
|
|
|
FIREWORKS_API_KEY: "Fireworks LLM key (only if a fireworks: model is used).",
|
|
|
|
|
|
GITHUB_APP_CLIENT_SECRET: "GitHub App OAuth client secret (dashboard login).",
|
|
|
|
|
|
GITHUB_APP_PRIVATE_KEY: "GitHub App private key PEM (installation-token minting).",
|
|
|
|
|
|
GITHUB_PAT: "GitHub PAT fallback (optional).",
|
|
|
|
|
|
GITHUB_WEBHOOK_SECRET: "GitHub webhook signature secret (prod-required).",
|
|
|
|
|
|
JUDGE_ANTHROPIC_API_KEY: "Eval judge key (optional; falls back to ANTHROPIC_API_KEY).",
|
|
|
|
|
|
LANGSMITH_API_KEY: "LangSmith key (dev).",
|
|
|
|
|
|
LANGSMITH_API_KEY_PROD: "LangSmith key (prod / deployed sandbox).",
|
|
|
|
|
|
LANGCHAIN_API_KEY: "LangSmith key alt name (fallback).",
|
|
|
|
|
|
LINEAR_API_KEY: "Linear API key (optional).",
|
|
|
|
|
|
LINEAR_WEBHOOK_SECRET: "Linear webhook signature secret (required when Linear is wired).",
|
|
|
|
|
|
RUNLOOP_API_KEY: "Runloop sandbox key (only if SANDBOX_TYPE=runloop).",
|
|
|
|
|
|
SLACK_BOT_TOKEN: "Slack bot token (optional).",
|
|
|
|
|
|
SLACK_CLIENT_SECRET: "Slack OAuth client secret.",
|
|
|
|
|
|
SLACK_SIGNING_SECRET: "Slack webhook signing secret (prod-required).",
|
|
|
|
|
|
TOKEN_ENCRYPTION_KEY: "Fernet key(s) for per-user GitHub-token encryption (REQUIRED).",
|
|
|
|
|
|
USER_ID_API_KEY_MAP: "JSON map of user id -> API key for per-user auth (optional, sensitive).",
|
|
|
|
|
|
X_SERVICE_AUTH_JWT_SECRET: "Service-auth JWT secret (optional).",
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* IaC-managed SSM config: stable / derivable values owned in code, per env.
|
|
|
|
|
|
* Values are functions of envName so dev/prod render correct hosts.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Anything operationally-variable or env-specific-unknown is deliberately NOT
|
|
|
|
|
|
* here — see OUT_OF_BAND_SSM.
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function iacManagedSsm(env: EnvName): Record<string, string> {
|
|
|
|
|
|
// Public host = seahaven.com (the migration's new AWS public face; confirmed by
|
|
|
|
|
|
// recon: seahaven.com Route53 zone + *.seahaven.com ACM cert are live on the ALB
|
|
|
|
|
|
// — distinct from the on-prem seahavenind.com). dev = openswe-dev, prod = openswe.
|
|
|
|
|
|
const host = `https://openswe${env === "dev" ? "-dev" : ""}.seahaven.com`;
|
2026-06-27 19:29:03 -04:00
|
|
|
|
// Repo targeting is PER-ENV: dev drives the disposable sandbox repo in the
|
|
|
|
|
|
// dedicated seahaven-open-swe-dev org (isolates dev-agent activity from the real
|
|
|
|
|
|
// Sea Haven org); prod stays on the Sea Haven org pilot repo. fetch-config's owner
|
|
|
|
|
|
// GUARD honors this value (rejecting only blank / the upstream langchain-ai org).
|
|
|
|
|
|
const repo =
|
|
|
|
|
|
env === "dev"
|
|
|
|
|
|
? { owner: "seahaven-open-swe-dev", name: "openswe-dev-sandbox" }
|
|
|
|
|
|
: { owner: "Sea-Haven-Industries", name: "open-swe-pilot" };
|
|
|
|
|
|
const managed: Record<string, string> = {
|
2026-06-26 16:07:23 -04:00
|
|
|
|
// Sandbox provider — plan keeps stock langsmith (T9). Stable.
|
|
|
|
|
|
SANDBOX_TYPE: "langsmith",
|
2026-06-27 19:29:03 -04:00
|
|
|
|
DEFAULT_REPO_OWNER: repo.owner,
|
|
|
|
|
|
// Repo-owner allowlist (comma list) — the env's org. The app gates triggers on this.
|
|
|
|
|
|
ALLOWED_GITHUB_ORGS: repo.owner,
|
|
|
|
|
|
DEFAULT_REPO_NAME: repo.name,
|
2026-06-26 16:07:23 -04:00
|
|
|
|
// Dashboard URLs — derived from the public host.
|
|
|
|
|
|
DASHBOARD_BASE_URL: host,
|
|
|
|
|
|
DASHBOARD_API_BASE_URL: host,
|
|
|
|
|
|
DASHBOARD_ALLOWED_ORIGINS: host,
|
feat: migrate model providers to Bedrock (Claude) + Fireworks (everything else) (#62)
* feat: switch model providers to AWS Bedrock (Claude) and Fireworks (non-Claude)
Migrate off direct provider APIs: AWS Bedrock for Anthropic/Claude via the
cross-region inference profile us.anthropic.claude-opus-4-8, Fireworks AI for
all non-Claude models. Drop OpenAI (gpt-5.5) and Google (gemini-3.5-flash)
entirely. DEFAULT_MODEL_ID is now Bedrock Claude; all Fireworks models stay
freely selectable for the agent and reviewer graphs and via team/profile
defaults.
- pyproject: add langchain-aws (ChatBedrockConverse + boto3)
- options.py: Bedrock Claude entry + default; remove openai/google entries
- model.py: bedrock_converse provider_model_kwargs (effort -> thinking budget),
region pin in make_model, bedrock<->fireworks fallback pairing, AWS_REGION/
FIREWORKS_API_KEY local-dev validation
- server.py: provider-aware fallback kwargs build
- sanitize_thinking_blocks: also sanitize ChatBedrockConverse thinking blocks
- model_fallback: treat transient botocore ClientError codes as fallback-worthy
- eval_jobs: repoint hardcoded eval model id to Bedrock Claude
- tests: repoint dropped model ids; drop obsolete google test module
* fix(bedrock): use adaptive thinking + output_config.effort for Opus 4.8
The handoff spec wired Bedrock Converse thinking as
{type: enabled, budget_tokens: N}, but Opus 4.7+ rejects that with a
ValidationException: thinking.type "enabled" is not supported; it requires
thinking.type "adaptive" plus output_config.effort. Verified by live invoke
against us.anthropic.claude-opus-4-8 (account 328440206208, us-east-1):
the enabled+budget shape 400s, adaptive+effort returns normally.
Map profile effort to additional_model_request_fields:
{thinking: {type: adaptive, display: summarized},
output_config: {effort: <low|medium|high|xhigh|max>}}
reusing anthropic_thinking_for/anthropic_effort_for. Update the two
subagent-model tests asserting the old shape.
* fix(deploy): seed Bedrock/Fireworks models, not the dropped anthropic:/openai: ids
Model selection is store-driven, so seed_store.sh's team_settings/default seed is
what runs in prod. It still seeded the removed providers, which would fail at runtime
after the migration:
- agent/builder: anthropic:claude-opus-4-8 -> bedrock_converse:us.anthropic.claude-opus-4-8
- reviewer: openai:gpt-5.5 (dropped) -> bedrock_converse:us.anthropic.claude-opus-4-8
(set SEED_REVIEWER_MODEL to a Fireworks model for a cross-family reviewer)
- fetch-config REQUIRED_PROVIDER_KEYS default ANTHROPIC_API_KEY,OPENAI_API_KEY ->
FIREWORKS_API_KEY (Bedrock auths via host IAM role; dropping the old keys would
otherwise fail-fast at boot)
- docs (DEPLOYMENT/ROTATION/put-config) updated to match.
Surfaced by the cross-family review + verified against deploy/.
* fix(bedrock): security-review NITs — region resolution, error sanitization, reasoning-block strip
From /sh-security-review (all confirmed-low):
- model.py: resolve region from AWS_REGION OR AWS_DEFAULT_REGION (matches
validate_local_dev_llm_config) so the validated region is the one actually used.
- model_fallback.py: sanitize Bedrock AccessDenied/ResourceNotFound errors to the
error code only, so the role ARN + account id in the raw botocore message never
reach logs or the user channel (CWE-209).
- sanitize_thinking_blocks.py: also strip empty Bedrock reasoning_content blocks
(Converse emits reasoning_content, not thinking) so the middleware is not a no-op
on Bedrock; + unit tests. (Empty blocks replay fine today; defensive.)
* deploy(bedrock): grant instance-role Bedrock invoke + repoint LLM_MODEL_ID / eval model ids
Deployment-readiness for the Bedrock migration (PR #62):
- instance-role.ts: least-privilege bedrock:InvokeModel[WithResponseStream] on the
us.anthropic.claude-opus-4-8 inference-profile ARN + the foundation-model ARN in
each routed region (us-east-1/2, us-west-2). The model runs in the server process
on the box, so the EC2 instance role is the principal. Simulator-verified (allowed
for opus-4-8, implicitDeny for other models) and synth-verified. Passed the
mandatory GPT-4.1 IAM cross-review (no blockers, least-privilege confirmed).
- config-store.ts: IaC SSM LLM_MODEL_ID anthropic:claude-opus-4-8 ->
bedrock_converse:us.anthropic.claude-opus-4-8. This SSM value overrides
seed_store.sh's default via pick precedence, so the seed-script fix alone was
insufficient — both sources now point at the supported Bedrock id.
- infra/README.md + evals/reviewer/config.toml: repoint stale anthropic:/google_genai:
ids to the Bedrock id (config.toml's model_id was an active, now-broken value).
AWS_REGION is already wired via user-data.sh (IMDS -> boot.env), so no change needed there.
* chore(secrets): drop OPENAI/GOOGLE/GROQ key shells (revoked, providers removed)
Those three providers were dropped in the Bedrock/Fireworks migration and their keys
revoked; the live Secrets Manager objects (open-swe-{dev,prod}/{OPENAI,GOOGLE,GROQ}_API_KEY)
were deleted (7-day recovery). Remove them from the IaC so a future cdk deploy does not
recreate the shells, and from fetch-config's mirror array so boot stops requesting them:
- config-store.ts SECRET_VARS + descriptions (28 -> 25 shells)
- fetch-config.sh SECRET_VARS array (kept in lockstep)
- put-config.sh: drop the put_secret lines; ANTHROPIC_API_KEY re-labelled optional
(eval judge only — Bedrock builder/reviewer auth via the host IAM role).
REQUIRED_PROVIDER_KEYS is not set in SSM, so it uses the FIREWORKS_API_KEY default.
2026-06-29 15:57:19 -04:00
|
|
|
|
// Primary builder model. seed_store.sh's `pick` precedence is
|
|
|
|
|
|
// OPENSWE_AGENT_MODEL > SEED_AGENT_MODEL > LLM_MODEL_ID > script default, so this
|
|
|
|
|
|
// SSM value overrides the seed-script default — it MUST be a supported id. Post
|
|
|
|
|
|
// Bedrock/Fireworks migration the only Bedrock-Claude id is the inference profile;
|
|
|
|
|
|
// `anthropic:claude-opus-4-8` was removed from SUPPORTED_MODELS.
|
|
|
|
|
|
LLM_MODEL_ID: "bedrock_converse:us.anthropic.claude-opus-4-8",
|
2026-06-26 16:07:23 -04:00
|
|
|
|
};
|
2026-06-27 19:29:03 -04:00
|
|
|
|
// Dev e2e smoke: seed the owner's user_mapping so an @openswe comment from the
|
|
|
|
|
|
// triggering GitHub login resolves (an unmapped commenter is silently skipped).
|
|
|
|
|
|
// Dev-only — prod seeds its mappings via its own operator config. login:email.
|
|
|
|
|
|
if (env === "dev") {
|
|
|
|
|
|
managed.SEED_USER_MAPPINGS = "amoussa1229:adam@seahavenind.com";
|
|
|
|
|
|
}
|
|
|
|
|
|
return managed;
|
2026-06-26 16:07:23 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Out-of-band SSM config: NOT created by CDK. Listed for documentation and for
|
|
|
|
|
|
* `put-config.sh` to populate before the box boots. Each MUST stay out of IaC
|
|
|
|
|
|
* because its value is operationally-variable or env-specific and unknown at
|
|
|
|
|
|
* synth time — making it CDK-managed would either clobber the operator value on
|
|
|
|
|
|
* the next deploy (e.g. DEFAULT_SANDBOX_SNAPSHOT_ID) or hardcode a secret-ish id.
|
|
|
|
|
|
*/
|
|
|
|
|
|
export const OUT_OF_BAND_SSM: readonly string[] = [
|
|
|
|
|
|
// Sandbox snapshot id — changes on EVERY snapshot rebuild. MUST NOT be
|
|
|
|
|
|
// CDK-managed or a deploy clobbers it. Required for SANDBOX_TYPE=langsmith.
|
|
|
|
|
|
"DEFAULT_SANDBOX_SNAPSHOT_ID",
|
|
|
|
|
|
// GitHub App identifiers — set when the per-env GitHub App is created.
|
|
|
|
|
|
"GITHUB_APP_ID",
|
|
|
|
|
|
"GITHUB_APP_CLIENT_ID",
|
|
|
|
|
|
"GITHUB_APP_INSTALLATION_ID",
|
|
|
|
|
|
"GITHUB_OAUTH_PROVIDER_ID",
|
|
|
|
|
|
// LangSmith deployment coordinates (prod tenant/urls/endpoints).
|
|
|
|
|
|
"LANGSMITH_TENANT_ID_PROD",
|
|
|
|
|
|
"LANGSMITH_URL_PROD",
|
|
|
|
|
|
"LANGSMITH_ENDPOINT",
|
|
|
|
|
|
"LANGSMITH_ENDPOINT_PROD",
|
|
|
|
|
|
"LANGSMITH_HOST_API_URL",
|
|
|
|
|
|
"LANGGRAPH_URL",
|
|
|
|
|
|
"LANGGRAPH_URL_PROD",
|
|
|
|
|
|
"LANGCHAIN_REVISION_ID",
|
|
|
|
|
|
// Slack workspace ids — set after the Slack app is installed.
|
|
|
|
|
|
"SLACK_CLIENT_ID",
|
|
|
|
|
|
"SLACK_TEAM_ID",
|
|
|
|
|
|
"SLACK_BOT_USER_ID",
|
|
|
|
|
|
"SLACK_BOT_USERNAME",
|
|
|
|
|
|
"SLACK_REPO_OWNER",
|
|
|
|
|
|
"SLACK_REPO_NAME",
|
|
|
|
|
|
// Access / observability allowlists — operator-curated.
|
|
|
|
|
|
"CONFIGURED_ADMINS",
|
|
|
|
|
|
"OBSERVABILITY_AUTHORIZED_EMAILS",
|
|
|
|
|
|
"PUBLIC_REPO_ORG_GATE",
|
|
|
|
|
|
"ALLOWED_GITHUB_REPOS",
|
|
|
|
|
|
// Optional integrations + tuning knobs (left to code defaults unless set).
|
|
|
|
|
|
"LLM_FALLBACK_MODEL_ID",
|
|
|
|
|
|
"DATADOG_MCP_TOOLSETS",
|
|
|
|
|
|
"NOTION_MCP_CLIENT_NAME",
|
|
|
|
|
|
"API_STANDARDS_SKILL_HANDLE",
|
|
|
|
|
|
"REPO_SNAPSHOT_BASE_IMAGE",
|
|
|
|
|
|
"REPO_SNAPSHOT_BUILD_TIMEOUT_SECONDS",
|
|
|
|
|
|
"REPO_SNAPSHOT_STALE_BUILD_SECONDS",
|
|
|
|
|
|
] as const;
|
|
|
|
|
|
|
|
|
|
|
|
export interface ConfigStoreProps {
|
|
|
|
|
|
readonly envName: EnvName;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Per-env Secrets Manager + SSM Parameter Store shells the boot hook reads.
|
|
|
|
|
|
* Instantiated from OpenSweStack. Synth-able now (T11); values populated
|
|
|
|
|
|
* out-of-band BEFORE the EC2/T12 deploy. See infra/README.md "Config store".
|
|
|
|
|
|
*/
|
|
|
|
|
|
export class ConfigStore extends Construct {
|
|
|
|
|
|
public readonly secrets: secretsmanager.CfnSecret[] = [];
|
|
|
|
|
|
public readonly params: ssm.StringParameter[] = [];
|
|
|
|
|
|
|
|
|
|
|
|
constructor(scope: Construct, id: string, props: ConfigStoreProps) {
|
|
|
|
|
|
super(scope, id);
|
|
|
|
|
|
const env = props.envName;
|
|
|
|
|
|
|
|
|
|
|
|
// --- 1) Secret shells (value-LESS; populated out-of-band) ----------------
|
|
|
|
|
|
for (const varName of SECRET_VARS) {
|
|
|
|
|
|
const secret = new secretsmanager.CfnSecret(this, `Secret-${varName}`, {
|
|
|
|
|
|
name: `open-swe-${env}/${varName}`,
|
|
|
|
|
|
description: SECRET_DESCRIPTIONS[varName] ?? `open-swe ${varName}`,
|
|
|
|
|
|
// Deliberately NO secretString / generateSecretString: CloudFormation
|
|
|
|
|
|
// creates an empty secret, so the out-of-band value is never clobbered.
|
|
|
|
|
|
});
|
|
|
|
|
|
// RETAIN: a stack teardown must not destroy operator-set secret material.
|
2026-06-29 10:51:49 -04:00
|
|
|
|
//
|
|
|
|
|
|
// GOTCHA — RETAIN + fixed name orphans these shells on a FAILED FIRST
|
|
|
|
|
|
// CREATE. If the stack's initial create fails and rolls back, RETAIN keeps
|
|
|
|
|
|
// the shells instead of deleting them; the stack is then gone but the
|
|
|
|
|
|
// secrets survive, still holding the global `open-swe-<env>/<VAR>` names.
|
|
|
|
|
|
// Every later create then fails with `AlreadyExists` (and a normal
|
|
|
|
|
|
// delete-secret keeps the name reserved for the 7–30 day recovery window,
|
|
|
|
|
|
// so it does NOT clear the deadlock). Recovery: before re-creating the
|
|
|
|
|
|
// stack, force-delete the orphans so the names free immediately, e.g.
|
|
|
|
|
|
// aws secretsmanager list-secrets --filters Key=name,Values=open-swe-<env>/ \
|
|
|
|
|
|
// --query 'SecretList[].Name' --output text | tr '\t' '\n' | while read n; do
|
|
|
|
|
|
// aws secretsmanager delete-secret --secret-id "$n" \
|
|
|
|
|
|
// --force-delete-without-recovery; done
|
|
|
|
|
|
// Only force-delete shells that are EMPTY (no value version) — a populated
|
|
|
|
|
|
// secret holds real operator material. This bites on teardown/rebuild, a
|
|
|
|
|
|
// secret logical-id change/refactor, or standing up a new env — NOT on
|
|
|
|
|
|
// routine updates of an already-created stack. (Hit on prod 2026-06-29.)
|
2026-06-26 16:07:23 -04:00
|
|
|
|
secret.applyRemovalPolicy(cdk.RemovalPolicy.RETAIN);
|
|
|
|
|
|
this.secrets.push(secret);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- 2) IaC-managed SSM config (real, derivable values) ------------------
|
|
|
|
|
|
const managed = iacManagedSsm(env);
|
|
|
|
|
|
for (const [varName, value] of Object.entries(managed)) {
|
|
|
|
|
|
this.params.push(
|
|
|
|
|
|
new ssm.StringParameter(this, `Param-${varName}`, {
|
|
|
|
|
|
parameterName: `/open-swe-${env}/${varName}`,
|
|
|
|
|
|
stringValue: value,
|
|
|
|
|
|
description: `IaC-managed open-swe ${varName} (${env}).`,
|
|
|
|
|
|
tier: ssm.ParameterTier.STANDARD,
|
|
|
|
|
|
}),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|