@raindancers/raindancers-crew 0.0.0 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsii +1026 -3
- package/API.md +1459 -326
- package/README.md +258 -0
- package/docs/spec-ecs-crew-construct.md +200 -0
- package/lib/crew-backup-bucket.js +1 -1
- package/lib/crew-webhook-ingress.d.ts +104 -0
- package/lib/crew-webhook-ingress.js +111 -0
- package/lib/ecs-crew-host.d.ts +247 -0
- package/lib/ecs-crew-host.js +383 -0
- package/lib/fargate-crew-base.js +1 -1
- package/lib/fargate-crew.js +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.js +3 -1
- package/lib/remote-crew-instance.js +1 -1
- package/package.json +2 -2
- package/src/assets/ecs-host-bootstrap.sh +205 -0
- package/src/crew-webhook-ingress.ts +175 -0
- package/src/ecs-crew-host.ts +616 -0
- package/src/index.ts +2 -0
package/.jsii
CHANGED
|
@@ -9030,7 +9030,7 @@
|
|
|
9030
9030
|
},
|
|
9031
9031
|
"name": "@raindancers/raindancers-crew",
|
|
9032
9032
|
"readme": {
|
|
9033
|
-
"markdown": "# @raindancers/raindancers-crew\n\nA CDK construct that provisions a **self-hosted [KiroCrew](https://github.com/kirodotdev/KiroCrew) gateway** on a single EC2 instance in your own AWS account, reached over **SSM Session Manager** — no inbound ports, no SSH key.\n\nIt is a pipeline-native, version-controlled port of the upstream `kirocrew-ec2` CloudFormation template. Where the native `kirocrew cloud launch` is an imperative one-shot, this construct lets you deploy the same shape **through your own CDK pipeline**, under **your** naming, permissions boundary, and OIDC deploy role — so a remote crew becomes a reviewed, repeatable, diffable artifact like everything else you ship.\n\n## Getting started\n\n### 1. Install\n\n```bash\nnpm install @raindancers/raindancers-crew\n```\n\nThe package targets `aws-cdk-lib` ^2.260.0 and `constructs` ^10 (peer dependencies — your app supplies them).\n\n### 2. Define a stack\n\nA complete stack that stands up an EC2 crew with off-box backup. Everything is\ntyped and compiles as-is — fill in your account, region, VPC lookup, and\npermissions-boundary ARN.\n\n```ts\nimport { App, Stack, StackProps } from 'aws-cdk-lib';\nimport * as ec2 from 'aws-cdk-lib/aws-ec2';\nimport { Construct } from 'constructs';\nimport {\n RemoteCrewInstance,\n CrewArchitecture,\n CrewBackupBucket,\n} from '@raindancers/raindancers-crew';\n\nclass CrewStack extends Stack {\n constructor(scope: Construct, id: string, props: StackProps) {\n super(scope, id, props);\n\n // Your existing VPC (or ec2.Vpc.fromLookup(...)).\n const vpc = ec2.Vpc.fromLookup(this, 'Vpc', { isDefault: true });\n\n // Durable, versioned, KMS-encrypted backup destination.\n const backup = new CrewBackupBucket(this, 'CrewBackup');\n\n new RemoteCrewInstance(this, 'Crew', {\n vpc,\n // REQUIRED: the instance runs a prompt-injectable agent, so its role\n // must be capped by a permissions boundary you pre-create.\n permissionsBoundaryArn:\n 'arn:aws:iam::123456789012:policy/kirocrew-ec2-boundary',\n architecture: CrewArchitecture.ARM64,\n instanceType: new ec2.InstanceType('m7g.2xlarge'),\n // Pin a released tag for reproducible deploys — the default `main` drifts.\n source: { kirocrewRef: 'v0.8.0' },\n // Off-box backup: grants scoped write + installs a daily snapshot timer.\n backupBucket: backup,\n backupSchedule: 'daily',\n });\n }\n}\n\nconst app = new App();\nnew CrewStack(app, 'RemoteCrew', {\n env: { account: '123456789012', region: 'eu-west-2' },\n});\napp.synth();\n```\n\n### 3. Deploy through your pipeline\n\nThis is a plain CDK stack — deploy it however you deploy everything else\n(a CDK Pipelines / agentl stage, or `cdk deploy` from a keyless-OIDC CI job).\nThe `WaitCondition` blocks stack completion until the gateway is actually\nserving, so a green deploy means a live crew (and a failed bootstrap rolls the\nstack back with the setup-log tail in the failure reason).\n\n```bash\ncdk deploy RemoteCrew\n```\n\n### 4. Connect\n\nAccess is **SSM-only** — no inbound ports. Open a port-forward to the\nloopback dashboard and browse `http://127.0.0.1:5476`:\n\n```bash\n# The construct exports the instance id under a stable name derived from the\n# stackTag (default 'kirocrew'): kirocrew-<stackTag>-instance-id\nINSTANCE_ID=$(aws cloudformation list-exports \\\n --query \"Exports[?Name=='kirocrew-kirocrew-instance-id'].Value\" --output text)\n\naws ssm start-session --target \"$INSTANCE_ID\" \\\n --document-name AWS-StartPortForwardingSession \\\n --parameters '{\"portNumber\":[\"5476\"],\"localPortNumber\":[\"5476\"]}'\n```\n\n(Or use the upstream `kirocrew cloud connect`, which mints the dashboard token\non the box and opens the tunnel for you.)\n\n### 5. Verify backup\n\nThe daily timer pushes a redaction-scrubbed snapshot to the backup bucket. Fire\none immediately and confirm it landed:\n\n```bash\n# On the instance (via SSM Session Manager):\nsudo systemctl start kirocrew-backup.service\nsudo journalctl -u kirocrew-backup.service --no-pager | tail\n\n# From your workstation — the stable key a replacement instance restores from:\naws s3 ls \"s3://<backup-bucket>/crew-snapshots/latest.tar\"\n```\n\nTo rebuild a **replacement** instance from backup, deploy a fresh `CrewStack`\npointing at the same bucket, then on the new box run\n`sudo kirocrew-restore-from-s3` (pulls `latest.tar`, stops the gateway,\nrestores in replace mode, restarts).\n\n> **Container crew instead of an instance?** See [Fargate lane](#fargate-lane)\n> below — swap `RemoteCrewInstance` for `FargateCrewBase` + `FargateCrew`.\n\nThe sections below are the per-construct reference.\n\n## What it creates\n\n| Resource | Notes |\n|---|---|\n| IAM role + instance profile | `AmazonSSMManagedInstanceCore` + a **required permissions boundary**; scoped `s3:GetObject` only when an S3 source is used |\n| Security group | **No inbound** by default (SSM-only); optional `tcp/22` from `allowSshCidr` (≤ /16); optional webhook port from a single source SG via `webhookIngress`; IPv6 egress when `enableIpv6` |\n| EC2 instance | Amazon Linux 2023, arch-aware AMI, **IMDSv2 enforced**, **encrypted gp3** root |\n| WaitConditionHandle + WaitCondition | Blocks stack completion until the gateway is actually serving on the loopback dashboard port |\n\n## Security posture (preserved from upstream)\n\n- **SSM-only access.** No inbound rules unless you explicitly pass `allowSshCidr`. Access is via SSM port-forward; the public DNS is diagnostics only.\n- **IMDSv2 required, hop limit 1.** KiroCrew runs a prompt-injectable agent that executes arbitrary tools — an SSRF/injection reaching the metadata endpoint must not be able to read the role's STS credentials via IMDSv1.\n- **Permissions boundary is mandatory** on the instance role.\n- **Node.js tarball is SHA-256-pinned** and verified before root extraction.\n- **Encrypted EBS root.**\n\n## Private dual-stack brain (55minutes posture)\n\nFor an always-on brain that egresses over IPv6 with **no public IPv4**, is woken\nby the native KiroCrew webhook, and runs as an autopilot crew that never\nidle-closes, compose the additive props below. Everything here is optional and\ndefaults off — omit it all and you get the SSM-only public-subnet box above.\n\n```ts\nimport * as ec2 from 'aws-cdk-lib/aws-ec2';\nimport { RemoteCrewInstance, CrewArchitecture } from '@raindancers/raindancers-crew';\n\n// vpc: a dual-stack VPC whose private subnets carry IPv6 CIDRs and route\n// ::/0 to an Egress-Only Internet Gateway (see \"What stays yours\" below).\n// ingestLambdaSg: the SG of the consumer's ingest Lambda / reverse proxy —\n// imported, this construct never creates it.\nnew RemoteCrewInstance(this, 'Brain', {\n vpc,\n permissionsBoundaryArn:\n 'arn:aws:iam::123456789012:policy/kirocrew-ec2-boundary',\n architecture: CrewArchitecture.ARM64,\n source: { kirocrewRef: 'v0.8.0' },\n\n // Private + dual-stack: IPv6 egress, no public IPv4.\n vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },\n associatePublicIp: false,\n enableIpv6: true,\n\n // Webhook reach from ONE source SG only (never a CIDR), authenticated by a\n // Bearer token fetched from Secrets Manager at boot (written to config.json\n // as hooks.webhook_token; the instance role gets GetSecretValue on this ARN).\n webhookIngress: { source: ingestLambdaSg },\n webhookTokenSecretArn:\n 'arn:aws:secretsmanager:eu-west-2:123456789012:secret:kc/webhook-token-AbCdEf',\n\n // Always-on: autopilot + never idle-close.\n crewRuntime: { autopilot: true, disableIdleClose: true },\n});\n```\n\n### What stays yours (this construct provisions none of it)\n\n`RemoteCrewInstance` consumes an `IVpc` and provisions no routing, so these live\nin your VPC / app, not the library:\n\n- **Egress-Only Internet Gateway** and the `::/0` IPv6 egress route — the VPC's\n concern. `enableIpv6` assigns the instance an IPv6 address and opens IPv6\n egress on its SG, but the route to the internet is yours.\n- **fck-nat (or managed NAT)** for any IPv4 egress you still need.\n- **The ingest Lambda and its security group** — you build it and pass its SG as\n `webhookIngress.source`. The construct only accepts it.\n- **Routable exposure of the webhook.** The KiroCrew gateway binds `127.0.0.1`\n only (it has no routable listener), so `webhookIngress` opens the SG but a\n **consumer-owned reverse proxy or SSH tunnel on the box** is what actually\n forwards `POST /api/hooks/agent` from the source SG to the loopback gateway.\n The dashboard stays loopback/SSM-only regardless.\n\n## Connecting\n\n`RemoteCrewInstance` provisions the box; **connection stays an operator action** (it is inherently imperative — mint a short-lived token on the instance and open an SSM port-forward). Use the upstream `kirocrew cloud connect` against the deployed instance id, or your own SSM `start-session` / port-forward wrapper.\n\n## Fargate lane\n\nFor a container-based crew there are two sibling constructs, mirroring the upstream `kirocrew-fargate-base` + `kirocrew-fargate-crew` split:\n\n- **`FargateCrewBase`** — one per account/region: the ECS cluster crew tasks run on plus an egress-only (no-inbound) task security group. Deleting a crew must not delete the shared cluster, so this is separate.\n- **`FargateCrew`** — one per crew: the execution role (secret read scoped to `kirocrew/crew/<crew>/*`, log write, optional private-ECR pull), the **zero-policy task role** (the running container's blast radius — it must never gain `secretsmanager:GetSecretValue`), and the crew's log group. All names are derived from the crew name.\n\n```ts\nimport { FargateCrewBase, FargateCrew } from '@raindancers/raindancers-crew';\n\nconst base = new FargateCrewBase(this, 'CrewBase', { vpc });\nnew FargateCrew(this, 'Crew', {\n crew: 'fiftyfive',\n // permissionsBoundaryArn: '...', // optional until the shared boundary creator lands\n // ecrRepositoryArn: '...', // only for a private image; public registry needs no grant\n});\n```\n\nSecurity invariants preserved from upstream: task role has no policies and never reads secrets; execution-role secret read is crew-scoped with individually-listed actions (no prefix wildcards); both assume-role trusts carry an `aws:SourceAccount` condition. The permissions boundary is **optional** here (a declared degraded mode) because no creator for the crew boundary exists yet — unlike the EC2 lane, where it is mandatory.\n\n**EC2 vs Fargate:** EC2 gives a persistent box with local disk (the crew's memory/knowledge DBs live on the instance) and is the native launcher's default; Fargate is more ephemeral and expects external persistence. For a remote crew that remembers across sessions, EC2 is usually the better fit.\n\n## Backing up the crew's learnings\n\nA remote crew's value is its accumulated memory, lessons, and knowledge — which on the EC2 lane live on the instance's local disk. KiroCrew's built-in backup (`kirocrew snapshot`) produces a redaction-scrubbed bundle (the signing key, `.env`, and execution logs never ship), but writes it **locally** — so it survives corruption, not instance loss. These constructs add the missing **off-box durability**.\n\n`CrewBackupBucket` provisions a hardened destination: SSE-KMS (rotating key), all public access blocked, TLS-only, **versioned**, with a lifecycle rule expiring stale noncurrent versions. Bucket and key `RETAIN` on stack delete, so the backups outlive a teardown.\n\n```ts\nimport { CrewBackupBucket, RemoteCrewInstance } from '@raindancers/raindancers-crew';\n\nconst backup = new CrewBackupBucket(this, 'CrewBackup');\n\nnew RemoteCrewInstance(this, 'Crew', {\n vpc,\n permissionsBoundaryArn: '...',\n backupBucket: backup, // grants scoped write + installs a daily timer\n backupSchedule: 'daily', // systemd OnCalendar\n});\n```\n\nOn the **EC2 lane** this grants the instance role scoped write, installs a **systemd timer** that runs `kirocrew snapshot --purpose backup` and uploads the newest bundle to S3 (a timestamped key for history plus a stable `latest.tar`), and installs a `kirocrew-restore-from-s3` helper. On the **Fargate lane**, pass the same bucket to `FargateCrew` — it grants the **task role** (the running container) write, since the container runs its own snapshot push.\n\n### Restore (rebuilding a replacement crew)\n\n`kirocrew restore <bundle> --mode replace|merge`:\n\n- **replace** clears the target's memory/knowledge trees and rebuilds them from the bundle (the knowledge DB and memory stores are replaced wholesale, not row-merged). Restore validates database integrity and refuses a truncated bundle; `sel_hmac.key` is regenerated (not restored). Use on a fresh replacement instance.\n- **merge** layers the bundle onto existing state without clearing. Use to seed a crew you want to keep.\n\nOn an EC2 instance provisioned with a backup bucket, `sudo kirocrew-restore-from-s3` pulls `latest.tar`, stops the gateway, restores in **replace** mode, and restarts — a one-command rebuild.\n\n## License\n\nApache-2.0\n"
|
|
9033
|
+
"markdown": "# @raindancers/raindancers-crew\n\nA CDK construct that provisions a **self-hosted [KiroCrew](https://github.com/kirodotdev/KiroCrew) gateway** on a single EC2 instance in your own AWS account, reached over **SSM Session Manager** — no inbound ports, no SSH key.\n\nIt is a pipeline-native, version-controlled port of the upstream `kirocrew-ec2` CloudFormation template. Where the native `kirocrew cloud launch` is an imperative one-shot, this construct lets you deploy the same shape **through your own CDK pipeline**, under **your** naming, permissions boundary, and OIDC deploy role — so a remote crew becomes a reviewed, repeatable, diffable artifact like everything else you ship.\n\n## Architecture\n\nWhat `RemoteCrewInstance` creates (solid) and what your VPC/app owns (dashed). The default is the SSM-only public-subnet box; the IPv6 egress and webhook ingress are opt-in props.\n\n```mermaid\nflowchart TB\n subgraph vpc[\"Your VPC (you own routing)\"]\n subgraph subnet[\"Subnet (public, or private-with-egress)\"]\n instance[\"EC2 instance<br/>Amazon Linux 2023, IMDSv2<br/>encrypted gp3 root<br/>kirocrew gateway on 127.0.0.1:5476\"]\n sg[\"Security group<br/>no inbound by default<br/>IPv6 egress if enableIpv6<br/>webhook port if webhookIngress\"]\n instance --- sg\n end\n eigw([\"Egress-Only IGW<br/>(consumer-owned, IPv6)\"])\n nat([\"NAT / fck-nat<br/>(consumer-owned, IPv4)\"])\n proxy([\"Reverse proxy<br/>(consumer-owned, fronts loopback webhook)\"])\n end\n\n role[\"IAM role<br/>SSM core + required permissions boundary<br/>scoped S3 GetObject / secret GetSecretValue\"]\n wait[\"WaitCondition<br/>blocks stack until gateway is healthy\"]\n operator([\"Operator\"])\n secret[(\"Secrets Manager<br/>webhook Bearer token\")]\n ingest([\"Ingest Lambda SG<br/>(consumer-owned)\"])\n\n instance --- role\n instance -.-> wait\n operator -- \"SSM port-forward (no inbound)\" --> instance\n instance -. \"IPv6 egress\" .-> eigw\n instance -. \"IPv4 egress\" .-> nat\n ingest -. \"webhook, source-SG only\" .-> proxy -.-> instance\n instance -. \"fetch token at boot\" .-> secret\n\n classDef owned fill:#e8f0fe,stroke:#4285f4;\n classDef consumer fill:#f5f5f5,stroke:#999,stroke-dasharray:4 3;\n class instance,sg,role,wait owned;\n class eigw,nat,proxy,ingest,secret consumer;\n```\n\n## Getting started\n\n### 1. Install\n\n```bash\nnpm install @raindancers/raindancers-crew\n```\n\nThe package targets `aws-cdk-lib` ^2.260.0 and `constructs` ^10 (peer dependencies — your app supplies them).\n\n### 2. Define a stack\n\nA complete stack that stands up an EC2 crew with off-box backup. Everything is\ntyped and compiles as-is — fill in your account, region, VPC lookup, and\npermissions-boundary ARN.\n\n```ts\nimport { App, Stack, StackProps } from 'aws-cdk-lib';\nimport * as ec2 from 'aws-cdk-lib/aws-ec2';\nimport { Construct } from 'constructs';\nimport {\n RemoteCrewInstance,\n CrewArchitecture,\n CrewBackupBucket,\n} from '@raindancers/raindancers-crew';\n\nclass CrewStack extends Stack {\n constructor(scope: Construct, id: string, props: StackProps) {\n super(scope, id, props);\n\n // Your existing VPC (or ec2.Vpc.fromLookup(...)).\n const vpc = ec2.Vpc.fromLookup(this, 'Vpc', { isDefault: true });\n\n // Durable, versioned, KMS-encrypted backup destination.\n const backup = new CrewBackupBucket(this, 'CrewBackup');\n\n new RemoteCrewInstance(this, 'Crew', {\n vpc,\n // REQUIRED: the instance runs a prompt-injectable agent, so its role\n // must be capped by a permissions boundary you pre-create.\n permissionsBoundaryArn:\n 'arn:aws:iam::123456789012:policy/kirocrew-ec2-boundary',\n architecture: CrewArchitecture.ARM64,\n instanceType: new ec2.InstanceType('m7g.2xlarge'),\n // Pin a released tag for reproducible deploys — the default `main` drifts.\n source: { kirocrewRef: 'v0.8.0' },\n // Off-box backup: grants scoped write + installs a daily snapshot timer.\n backupBucket: backup,\n backupSchedule: 'daily',\n });\n }\n}\n\nconst app = new App();\nnew CrewStack(app, 'RemoteCrew', {\n env: { account: '123456789012', region: 'eu-west-2' },\n});\napp.synth();\n```\n\n### 3. Deploy through your pipeline\n\nThis is a plain CDK stack — deploy it however you deploy everything else\n(a CDK Pipelines / agentl stage, or `cdk deploy` from a keyless-OIDC CI job).\nThe `WaitCondition` blocks stack completion until the gateway is actually\nserving, so a green deploy means a live crew (and a failed bootstrap rolls the\nstack back with the setup-log tail in the failure reason).\n\n```bash\ncdk deploy RemoteCrew\n```\n\n### 4. Connect\n\nAccess is **SSM-only** — no inbound ports. Open a port-forward to the\nloopback dashboard and browse `http://127.0.0.1:5476`:\n\n```bash\n# The construct exports the instance id under a stable name derived from the\n# stackTag (default 'kirocrew'): kirocrew-<stackTag>-instance-id\nINSTANCE_ID=$(aws cloudformation list-exports \\\n --query \"Exports[?Name=='kirocrew-kirocrew-instance-id'].Value\" --output text)\n\naws ssm start-session --target \"$INSTANCE_ID\" \\\n --document-name AWS-StartPortForwardingSession \\\n --parameters '{\"portNumber\":[\"5476\"],\"localPortNumber\":[\"5476\"]}'\n```\n\n(Or use the upstream `kirocrew cloud connect`, which mints the dashboard token\non the box and opens the tunnel for you.)\n\n### 5. Verify backup\n\nThe daily timer pushes a redaction-scrubbed snapshot to the backup bucket. Fire\none immediately and confirm it landed:\n\n```bash\n# On the instance (via SSM Session Manager):\nsudo systemctl start kirocrew-backup.service\nsudo journalctl -u kirocrew-backup.service --no-pager | tail\n\n# From your workstation — the stable key a replacement instance restores from:\naws s3 ls \"s3://<backup-bucket>/crew-snapshots/latest.tar\"\n```\n\nTo rebuild a **replacement** instance from backup, deploy a fresh `CrewStack`\npointing at the same bucket, then on the new box run\n`sudo kirocrew-restore-from-s3` (pulls `latest.tar`, stops the gateway,\nrestores in replace mode, restarts).\n\n> **Container crew instead of an instance?** See [Fargate lane](#fargate-lane)\n> below — swap `RemoteCrewInstance` for `FargateCrewBase` + `FargateCrew`.\n\nThe sections below are the per-construct reference.\n\n## What it creates\n\n| Resource | Notes |\n|---|---|\n| IAM role + instance profile | `AmazonSSMManagedInstanceCore` + a **required permissions boundary**; scoped `s3:GetObject` only when an S3 source is used |\n| Security group | **No inbound** by default (SSM-only); optional `tcp/22` from `allowSshCidr` (≤ /16); optional webhook port from a single source SG via `webhookIngress`; IPv6 egress when `enableIpv6` |\n| EC2 instance | Amazon Linux 2023, arch-aware AMI, **IMDSv2 enforced**, **encrypted gp3** root |\n| WaitConditionHandle + WaitCondition | Blocks stack completion until the gateway is actually serving on the loopback dashboard port |\n\n## Security posture (preserved from upstream)\n\n- **SSM-only access.** No inbound rules unless you explicitly pass `allowSshCidr`. Access is via SSM port-forward; the public DNS is diagnostics only.\n- **IMDSv2 required, hop limit 1.** KiroCrew runs a prompt-injectable agent that executes arbitrary tools — an SSRF/injection reaching the metadata endpoint must not be able to read the role's STS credentials via IMDSv1.\n- **Permissions boundary is mandatory** on the instance role.\n- **Node.js tarball is SHA-256-pinned** and verified before root extraction.\n- **Encrypted EBS root.**\n\n## Private dual-stack brain (55minutes posture)\n\nFor an always-on brain that egresses over IPv6 with **no public IPv4**, is woken\nby the native KiroCrew webhook, and runs as an autopilot crew that never\nidle-closes, compose the additive props below. Everything here is optional and\ndefaults off — omit it all and you get the SSM-only public-subnet box above.\n\n```ts\nimport * as ec2 from 'aws-cdk-lib/aws-ec2';\nimport { RemoteCrewInstance, CrewArchitecture } from '@raindancers/raindancers-crew';\n\n// vpc: a dual-stack VPC whose private subnets carry IPv6 CIDRs and route\n// ::/0 to an Egress-Only Internet Gateway (see \"What stays yours\" below).\n// ingestLambdaSg: the SG of the consumer's ingest Lambda / reverse proxy —\n// imported, this construct never creates it.\nnew RemoteCrewInstance(this, 'Brain', {\n vpc,\n permissionsBoundaryArn:\n 'arn:aws:iam::123456789012:policy/kirocrew-ec2-boundary',\n architecture: CrewArchitecture.ARM64,\n source: { kirocrewRef: 'v0.8.0' },\n\n // Private + dual-stack: IPv6 egress, no public IPv4.\n vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },\n associatePublicIp: false,\n enableIpv6: true,\n\n // Webhook reach from ONE source SG only (never a CIDR), authenticated by a\n // Bearer token fetched from Secrets Manager at boot (written to config.json\n // as hooks.webhook_token; the instance role gets GetSecretValue on this ARN).\n webhookIngress: { source: ingestLambdaSg },\n webhookTokenSecretArn:\n 'arn:aws:secretsmanager:eu-west-2:123456789012:secret:kc/webhook-token-AbCdEf',\n\n // Always-on: autopilot + never idle-close.\n crewRuntime: { autopilot: true, disableIdleClose: true },\n});\n```\n\n### What stays yours (this construct provisions none of it)\n\n`RemoteCrewInstance` consumes an `IVpc` and provisions no routing, so these live\nin your VPC / app, not the library:\n\n- **Egress-Only Internet Gateway** and the `::/0` IPv6 egress route — the VPC's\n concern. `enableIpv6` assigns the instance an IPv6 address and opens IPv6\n egress on its SG, but the route to the internet is yours.\n- **fck-nat (or managed NAT)** for any IPv4 egress you still need.\n- **The ingest Lambda and its security group** — you build it and pass its SG as\n `webhookIngress.source`. The construct only accepts it.\n- **Routable exposure of the webhook.** The KiroCrew gateway binds `127.0.0.1`\n only (it has no routable listener), so `webhookIngress` opens the SG but a\n **consumer-owned reverse proxy or SSH tunnel on the box** is what actually\n forwards `POST /api/hooks/agent` from the source SG to the loopback gateway.\n The dashboard stays loopback/SSM-only regardless.\n\n## Examples\n\nWorked implementations for the common shapes. Each is a complete construct\ninstantiation against the real props — fill in your account, region, VPC, and\npermissions-boundary ARN.\n\n### 1. Minimal SSM-only crew (the simplest thing that works)\n\nA single crew box in a public subnet, reached only over SSM. No backup, no\nwebhook, defaults everywhere.\n\n```ts\nimport * as ec2 from 'aws-cdk-lib/aws-ec2';\nimport { RemoteCrewInstance } from '@raindancers/raindancers-crew';\n\nconst vpc = ec2.Vpc.fromLookup(this, 'Vpc', { isDefault: true });\n\nnew RemoteCrewInstance(this, 'Crew', {\n vpc,\n permissionsBoundaryArn:\n 'arn:aws:iam::123456789012:policy/kirocrew-ec2-boundary',\n // Pin a released tag for reproducible deploys — the default `main` drifts.\n source: { kirocrewRef: 'v0.8.0' },\n});\n```\n\n### 2. Crew with off-box backup\n\nAdd a hardened, versioned, KMS-encrypted backup bucket; the construct grants the\ninstance role write + read and installs a daily snapshot timer.\n\n```ts\nimport * as ec2 from 'aws-cdk-lib/aws-ec2';\nimport {\n RemoteCrewInstance,\n CrewBackupBucket,\n CrewArchitecture,\n} from '@raindancers/raindancers-crew';\n\nconst vpc = ec2.Vpc.fromLookup(this, 'Vpc', { isDefault: true });\nconst backup = new CrewBackupBucket(this, 'CrewBackup');\n\nnew RemoteCrewInstance(this, 'Crew', {\n vpc,\n permissionsBoundaryArn:\n 'arn:aws:iam::123456789012:policy/kirocrew-ec2-boundary',\n architecture: CrewArchitecture.ARM64,\n instanceType: new ec2.InstanceType('m7g.2xlarge'),\n source: { kirocrewRef: 'v0.8.0' },\n backupBucket: backup,\n backupSchedule: 'daily', // systemd OnCalendar expression\n backupPrefix: 'crew-snapshots/',\n});\n```\n\n### 3. Source from an S3 tarball instead of a git clone\n\nFor air-gapped or pinned-artifact deploys: the instance role is granted\n`s3:GetObject` on exactly that one object, nothing wider.\n\n```ts\nnew RemoteCrewInstance(this, 'Crew', {\n vpc,\n permissionsBoundaryArn:\n 'arn:aws:iam::123456789012:policy/kirocrew-ec2-boundary',\n source: {\n sourceBucket: 'my-artifacts-bucket',\n sourceKey: 'kirocrew/kirocrew-src-v0.8.0.tar.gz',\n },\n});\n```\n\n### 4. Private dual-stack always-on brain (the full 55minutes posture)\n\nPrivate subnet, IPv6 egress, no public IPv4, webhook reachable from one source\nSG, authenticated by a Secrets Manager token, running as an autopilot crew that\nnever idle-closes. See [Private dual-stack brain](#private-dual-stack-brain-55minutes-posture)\nabove for the prop-by-prop walkthrough.\n\n```ts\nimport * as ec2 from 'aws-cdk-lib/aws-ec2';\nimport { RemoteCrewInstance, CrewArchitecture } from '@raindancers/raindancers-crew';\n\n// ingestLambdaSg: the SG of your ingest Lambda / reverse proxy — imported.\nnew RemoteCrewInstance(this, 'Brain', {\n vpc,\n permissionsBoundaryArn:\n 'arn:aws:iam::123456789012:policy/kirocrew-ec2-boundary',\n architecture: CrewArchitecture.ARM64,\n source: { kirocrewRef: 'v0.8.0' },\n\n vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },\n associatePublicIp: false,\n enableIpv6: true,\n\n webhookIngress: { source: ingestLambdaSg },\n webhookTokenSecretArn:\n 'arn:aws:secretsmanager:eu-west-2:123456789012:secret:kc/webhook-token-AbCdEf',\n\n crewRuntime: { autopilot: true, disableIdleClose: true },\n});\n```\n\n### 5. Fargate lane — shared base + one crew\n\nFor a container-based crew: `FargateCrewBase` once per account/region (the ECS\ncluster + egress-only SG), then one `FargateCrew` per crew (its two roles + log\ngroup). Deleting a crew never touches the shared cluster.\n\n```ts\nimport * as ec2 from 'aws-cdk-lib/aws-ec2';\nimport {\n FargateCrewBase,\n FargateCrew,\n FargateCpuArchitecture,\n CrewBackupBucket,\n} from '@raindancers/raindancers-crew';\n\nconst vpc = ec2.Vpc.fromLookup(this, 'Vpc', { isDefault: true });\nconst backup = new CrewBackupBucket(this, 'CrewBackup');\n\n// One per account/region — the shared cluster + egress-only task SG.\nconst base = new FargateCrewBase(this, 'CrewBase', {\n vpc,\n cpuArchitecture: FargateCpuArchitecture.ARM64,\n});\n\n// One per crew — roles + log group. Task role gets the backup write grant\n// (the running container pushes snapshots), NEVER a secret-read grant.\nconst crew = new FargateCrew(this, 'ResearchCrew', {\n crew: 'research',\n logRetentionDays: 30,\n permissionsBoundaryArn:\n 'arn:aws:iam::123456789012:policy/kirocrew-crew-boundary',\n backupBucket: backup,\n});\n\n// base.cluster, base.securityGroup, crew.executionRole, crew.taskRole,\n// crew.logGroup, crew.secretNamePrefix are exposed for your RunTask launch spec.\n```\n\n### Access + webhook flow\n\nHow the crew is reached — SSM for the operator, the source-SG + reverse proxy\nfor the native webhook. Nothing dials the box directly.\n\n```mermaid\nsequenceDiagram\n actor Op as Operator\n participant SSM as SSM Session Manager\n participant GW as Gateway (127.0.0.1:5476)\n Op->>SSM: aws ssm start-session (port-forward)\n SSM->>GW: tunnel to loopback dashboard\n GW-->>Op: dashboard on localhost\n\n participant Src as Ingest Lambda (source SG)\n participant RP as Reverse proxy (consumer)\n participant Hook as Gateway /api/hooks/agent (loopback)\n Src->>RP: POST webhook (SG allows source only)\n RP->>Hook: forward with Bearer token\n Hook-->>RP: 202 accepted (agent turn queued)\n```\n\n## Connecting\n\n`RemoteCrewInstance` provisions the box; **connection stays an operator action** (it is inherently imperative — mint a short-lived token on the instance and open an SSM port-forward). Use the upstream `kirocrew cloud connect` against the deployed instance id, or your own SSM `start-session` / port-forward wrapper.\n\n## Fargate lane\n\nFor a container-based crew there are two sibling constructs, mirroring the upstream `kirocrew-fargate-base` + `kirocrew-fargate-crew` split:\n\n- **`FargateCrewBase`** — one per account/region: the ECS cluster crew tasks run on plus an egress-only (no-inbound) task security group. Deleting a crew must not delete the shared cluster, so this is separate.\n- **`FargateCrew`** — one per crew: the execution role (secret read scoped to `kirocrew/crew/<crew>/*`, log write, optional private-ECR pull), the **zero-policy task role** (the running container's blast radius — it must never gain `secretsmanager:GetSecretValue`), and the crew's log group. All names are derived from the crew name.\n\n```ts\nimport { FargateCrewBase, FargateCrew } from '@raindancers/raindancers-crew';\n\nconst base = new FargateCrewBase(this, 'CrewBase', { vpc });\nnew FargateCrew(this, 'Crew', {\n crew: 'fiftyfive',\n // permissionsBoundaryArn: '...', // optional until the shared boundary creator lands\n // ecrRepositoryArn: '...', // only for a private image; public registry needs no grant\n});\n```\n\nSecurity invariants preserved from upstream: task role has no policies and never reads secrets; execution-role secret read is crew-scoped with individually-listed actions (no prefix wildcards); both assume-role trusts carry an `aws:SourceAccount` condition. The permissions boundary is **optional** here (a declared degraded mode) because no creator for the crew boundary exists yet — unlike the EC2 lane, where it is mandatory.\n\n**EC2 vs Fargate:** EC2 gives a persistent box with local disk (the crew's memory/knowledge DBs live on the instance) and is the native launcher's default; Fargate is more ephemeral and expects external persistence. For a remote crew that remembers across sessions, EC2 is usually the better fit.\n\n## ECS-on-EC2 multi-crew host\n\n`EcsCrewHost` runs several isolated Kiro Crew instances on ONE self-provisioned EC2 host, each crew as its own ECS-on-EC2 container task. It builds on the same `FargateCrewBase` cluster and `FargateCrew` per-crew identity, adds the EC2 capacity, and wires the two-subnet host-NAT networking. It is strictly additive: `crewCount` defaults to 1, so a plain instantiation behaves like a single crew and existing consumers gain nothing new.\n\n```ts\nimport { EcsCrewHost, CrewBackupBucket } from '@raindancers/raindancers-crew';\nimport * as ec2 from 'aws-cdk-lib/aws-ec2';\n\nconst backup = new CrewBackupBucket(this, 'CrewBackup');\n\nnew EcsCrewHost(this, 'CrewFleet', {\n vpc, // you supply the two-subnet host-NAT VPC\n permissionsBoundaryArn: '...', // host role boundary (required)\n crewPermissionsBoundaryArn: '...', // kirocrew-crew-boundary for the crew roles\n instanceType: new ec2.InstanceType('m9g.xlarge'),\n crewCount: 3,\n crewDataVolumeSizeGb: 20,\n backupBucket: backup,\n stackTag: 'fiftyfive',\n});\n```\n\nWhat it creates:\n\n| Resource | Notes |\n|---|---|\n| ECS cluster + egress-only task SG | Reused from `FargateCrewBase` (one per account/region) |\n| Size-1 Auto Scaling Group + capacity provider | ONE self-provisioned host, arch-aware ECS-optimized AL2023 AMI, **IMDSv2 enforced**, **encrypted gp3** root. A size-1 ASG is still one EC2 host; the capacity provider is what registers it with the cluster so the L2 `Ec2Service` can schedule onto it |\n| Per-crew EC2 task definition + service | `awsvpc` network mode (each task its own ENI + private IP), `desiredCount: 1`, egress-only task SG, **no public IP**. Reuses each crew's `FargateCrew` task/execution role and `/kirocrew/crew/<crew>` log group |\n| Per-crew durable EBS | one encrypted **gp3** volume per crew, **`deleteOnTermination: false`** so a crew's `~/.kiro/crew` outlives an instance replacement. Resolved in the bootstrap by a stable filesystem **label**, never `/dev/sdf` (the Nitro NVMe layer renames it) |\n| Host role grant | scoped `ec2:ModifyInstanceAttribute` (tag-conditioned to KiroCrew ECS hosts) so the host disables its own source/dest check for NAT |\n\nNetworking model (you supply the VPC; the construct does NOT create a NAT Gateway, fck-nat, VPC endpoints, or an ALB):\n\n- **PUBLIC subnet** holds the host ENI + Elastic IP + the IGW route. The host egresses directly via the IGW.\n- **PRIVATE subnet** holds the crew task ENIs. Its `0.0.0.0/0` route points at the host ENI. The host does the NAT: the bootstrap sets `net.ipv4.ip_forward=1` and an iptables `MASQUERADE` rule, and the host disables source/dest check on its own ENI. Tasks have no public IPs.\n\nIsolation is container-level (shared kernel), accepted as sufficient: Graviton Nitro protects the box from other AWS tenants, and containers cover crew-to-crew separation. Two cautions this bakes into the props and tests:\n\n- **Host-OOM cross-crew blast radius.** Each crew container carries a SOFT `memoryReservationMiB` (for scheduling) and a HARD `memoryLimitMiB` (its ceiling). Hard caps bound each crew, but because the kernel is shared, if the sum of ACTUAL usage exceeds physical RAM the host OOM-killer can hit any crew. For a hard guarantee set the sum of hard caps at or below (physical RAM minus host + ECS-agent headroom). This is the accepted cost of container isolation versus microVMs.\n- **awsvpc ENI budget.** Each task takes one ENI, plus the host ENI, so you need at least `crewCount + 1` ENIs on the instance type. `crewCount` is validated 1..8. The bootstrap enables ENI trunking (`ECS_ENABLE_AWSVPC_TRUNKING`) which raises the per-instance task-ENI budget on smaller sizes; confirm the chosen `m9g` size carries `crewCount + 1` ENIs before you build.\n\n### Optional webhook ingress (`CrewWebhookIngress`)\n\nBecause each task has a real private VPC IP, an in-VPC Lambda can POST to a crew's `POST /api/hooks/agent` directly, with no VPC endpoint. `CrewWebhookIngress` is an OPTIONAL composable sub-construct (mirroring `CrewBackupBucket`): OFF by default, so an existing consumer gains no new resources. When instantiated it creates an SNS topic, an in-VPC arm64 Lambda under the boundary, and the ONE controlled inbound exception to the egress-only task model: a scoped ingress rule on the crew task SG from the Lambda's SG on the crew port only, never a CIDR. It ships no webhook-to-crew routing opinion; you supply the Lambda `code`.\n\n```ts\nimport { CrewWebhookIngress } from '@raindancers/raindancers-crew';\nimport * as lambda from 'aws-cdk-lib/aws-lambda';\n\nnew CrewWebhookIngress(this, 'Webhook', {\n vpc,\n host, // the EcsCrewHost above\n permissionsBoundaryArn: '...',\n code: lambda.Code.fromAsset('path/to/ingress-lambda'),\n});\n```\n\n## Backing up the crew's learnings\n\nA remote crew's value is its accumulated memory, lessons, and knowledge — which on the EC2 lane live on the instance's local disk. KiroCrew's built-in backup (`kirocrew snapshot`) produces a redaction-scrubbed bundle (the signing key, `.env`, and execution logs never ship), but writes it **locally** — so it survives corruption, not instance loss. These constructs add the missing **off-box durability**.\n\n`CrewBackupBucket` provisions a hardened destination: SSE-KMS (rotating key), all public access blocked, TLS-only, **versioned**, with a lifecycle rule expiring stale noncurrent versions. Bucket and key `RETAIN` on stack delete, so the backups outlive a teardown.\n\n```ts\nimport { CrewBackupBucket, RemoteCrewInstance } from '@raindancers/raindancers-crew';\n\nconst backup = new CrewBackupBucket(this, 'CrewBackup');\n\nnew RemoteCrewInstance(this, 'Crew', {\n vpc,\n permissionsBoundaryArn: '...',\n backupBucket: backup, // grants scoped write + installs a daily timer\n backupSchedule: 'daily', // systemd OnCalendar\n});\n```\n\nOn the **EC2 lane** this grants the instance role scoped write, installs a **systemd timer** that runs `kirocrew snapshot --purpose backup` and uploads the newest bundle to S3 (a timestamped key for history plus a stable `latest.tar`), and installs a `kirocrew-restore-from-s3` helper. On the **Fargate lane**, pass the same bucket to `FargateCrew` — it grants the **task role** (the running container) write, since the container runs its own snapshot push.\n\n### Restore (rebuilding a replacement crew)\n\n`kirocrew restore <bundle> --mode replace|merge`:\n\n- **replace** clears the target's memory/knowledge trees and rebuilds them from the bundle (the knowledge DB and memory stores are replaced wholesale, not row-merged). Restore validates database integrity and refuses a truncated bundle; `sel_hmac.key` is regenerated (not restored). Use on a fresh replacement instance.\n- **merge** layers the bundle onto existing state without clearing. Use to seed a crew you want to keep.\n\nOn an EC2 instance provisioned with a backup bucket, `sudo kirocrew-restore-from-s3` pulls `latest.tar`, stops the gateway, restores in **replace** mode, and restarts — a one-command rebuild.\n\n## License\n\nApache-2.0\n"
|
|
9034
9034
|
},
|
|
9035
9035
|
"repository": {
|
|
9036
9036
|
"type": "git",
|
|
@@ -9278,6 +9278,89 @@
|
|
|
9278
9278
|
],
|
|
9279
9279
|
"symbolId": "src/crew-backup-bucket:CrewBackupBucketProps"
|
|
9280
9280
|
},
|
|
9281
|
+
"@raindancers/raindancers-crew.CrewDataVolume": {
|
|
9282
|
+
"assembly": "@raindancers/raindancers-crew",
|
|
9283
|
+
"datatype": true,
|
|
9284
|
+
"docs": {
|
|
9285
|
+
"remarks": "The device name the construct asks for (for example `/dev/sdf`) is NOT the\nkernel device name on Nitro/Graviton, where every EBS volume surfaces as an\nunpredictable `/dev/nvmeXn1`. The bootstrap therefore resolves each volume by\na stable filesystem LABEL, never by the device path.",
|
|
9286
|
+
"stability": "stable",
|
|
9287
|
+
"summary": "How a per-crew durable EBS volume is exposed to the host and its container."
|
|
9288
|
+
},
|
|
9289
|
+
"fqn": "@raindancers/raindancers-crew.CrewDataVolume",
|
|
9290
|
+
"kind": "interface",
|
|
9291
|
+
"locationInModule": {
|
|
9292
|
+
"filename": "src/ecs-crew-host.ts",
|
|
9293
|
+
"line": 32
|
|
9294
|
+
},
|
|
9295
|
+
"name": "CrewDataVolume",
|
|
9296
|
+
"properties": [
|
|
9297
|
+
{
|
|
9298
|
+
"abstract": true,
|
|
9299
|
+
"docs": {
|
|
9300
|
+
"stability": "stable",
|
|
9301
|
+
"summary": "The crew this volume belongs to."
|
|
9302
|
+
},
|
|
9303
|
+
"immutable": true,
|
|
9304
|
+
"locationInModule": {
|
|
9305
|
+
"filename": "src/ecs-crew-host.ts",
|
|
9306
|
+
"line": 34
|
|
9307
|
+
},
|
|
9308
|
+
"name": "crew",
|
|
9309
|
+
"type": {
|
|
9310
|
+
"primitive": "string"
|
|
9311
|
+
}
|
|
9312
|
+
},
|
|
9313
|
+
{
|
|
9314
|
+
"abstract": true,
|
|
9315
|
+
"docs": {
|
|
9316
|
+
"stability": "stable",
|
|
9317
|
+
"summary": "The block device name requested at attach time (a hint, not the kernel name)."
|
|
9318
|
+
},
|
|
9319
|
+
"immutable": true,
|
|
9320
|
+
"locationInModule": {
|
|
9321
|
+
"filename": "src/ecs-crew-host.ts",
|
|
9322
|
+
"line": 36
|
|
9323
|
+
},
|
|
9324
|
+
"name": "deviceName",
|
|
9325
|
+
"type": {
|
|
9326
|
+
"primitive": "string"
|
|
9327
|
+
}
|
|
9328
|
+
},
|
|
9329
|
+
{
|
|
9330
|
+
"abstract": true,
|
|
9331
|
+
"docs": {
|
|
9332
|
+
"stability": "stable",
|
|
9333
|
+
"summary": "The stable filesystem label the bootstrap resolves and mounts by."
|
|
9334
|
+
},
|
|
9335
|
+
"immutable": true,
|
|
9336
|
+
"locationInModule": {
|
|
9337
|
+
"filename": "src/ecs-crew-host.ts",
|
|
9338
|
+
"line": 38
|
|
9339
|
+
},
|
|
9340
|
+
"name": "label",
|
|
9341
|
+
"type": {
|
|
9342
|
+
"primitive": "string"
|
|
9343
|
+
}
|
|
9344
|
+
},
|
|
9345
|
+
{
|
|
9346
|
+
"abstract": true,
|
|
9347
|
+
"docs": {
|
|
9348
|
+
"stability": "stable",
|
|
9349
|
+
"summary": "The host mount path the container bind-mounts for `~/.kiro/crew`."
|
|
9350
|
+
},
|
|
9351
|
+
"immutable": true,
|
|
9352
|
+
"locationInModule": {
|
|
9353
|
+
"filename": "src/ecs-crew-host.ts",
|
|
9354
|
+
"line": 40
|
|
9355
|
+
},
|
|
9356
|
+
"name": "mountPath",
|
|
9357
|
+
"type": {
|
|
9358
|
+
"primitive": "string"
|
|
9359
|
+
}
|
|
9360
|
+
}
|
|
9361
|
+
],
|
|
9362
|
+
"symbolId": "src/ecs-crew-host:CrewDataVolume"
|
|
9363
|
+
},
|
|
9281
9364
|
"@raindancers/raindancers-crew.CrewRuntime": {
|
|
9282
9365
|
"assembly": "@raindancers/raindancers-crew",
|
|
9283
9366
|
"datatype": true,
|
|
@@ -9428,6 +9511,946 @@
|
|
|
9428
9511
|
],
|
|
9429
9512
|
"symbolId": "src/remote-crew-instance-props:CrewSource"
|
|
9430
9513
|
},
|
|
9514
|
+
"@raindancers/raindancers-crew.CrewWebhookIngress": {
|
|
9515
|
+
"assembly": "@raindancers/raindancers-crew",
|
|
9516
|
+
"base": "constructs.Construct",
|
|
9517
|
+
"docs": {
|
|
9518
|
+
"remarks": "Nothing is created unless the\nconsumer instantiates it, so an existing consumer gains no new resources.\n\nBecause each crew task runs in awsvpc mode with a real private VPC IP, an\nin-VPC Lambda can POST to a crew's `POST /api/hooks/agent` DIRECTLY — no VPC\nendpoint, no PrivateLink, no ALB. This construct wires: an SNS topic, an\nin-VPC Lambda under the permissions boundary, and a scoped ingress rule on\nthe crew task security group from the Lambda's SG on the crew port ONLY.\nThat ingress rule is the single controlled inbound exception to the\negress-only task model.\n\nGreenfield: the construct wires the plumbing but ships no webhook-to-crew\nrouting opinion — the consumer supplies the Lambda {@link CrewWebhookIngressProps.code}.",
|
|
9519
|
+
"stability": "stable",
|
|
9520
|
+
"summary": "OPTIONAL, composable webhook-ingress path for {@link EcsCrewHost}, mirroring the optional {@link CrewBackupBucket } shape."
|
|
9521
|
+
},
|
|
9522
|
+
"fqn": "@raindancers/raindancers-crew.CrewWebhookIngress",
|
|
9523
|
+
"initializer": {
|
|
9524
|
+
"docs": {
|
|
9525
|
+
"stability": "stable"
|
|
9526
|
+
},
|
|
9527
|
+
"locationInModule": {
|
|
9528
|
+
"filename": "src/crew-webhook-ingress.ts",
|
|
9529
|
+
"line": 120
|
|
9530
|
+
},
|
|
9531
|
+
"parameters": [
|
|
9532
|
+
{
|
|
9533
|
+
"name": "scope",
|
|
9534
|
+
"type": {
|
|
9535
|
+
"fqn": "constructs.Construct"
|
|
9536
|
+
}
|
|
9537
|
+
},
|
|
9538
|
+
{
|
|
9539
|
+
"name": "id",
|
|
9540
|
+
"type": {
|
|
9541
|
+
"primitive": "string"
|
|
9542
|
+
}
|
|
9543
|
+
},
|
|
9544
|
+
{
|
|
9545
|
+
"name": "props",
|
|
9546
|
+
"type": {
|
|
9547
|
+
"fqn": "@raindancers/raindancers-crew.CrewWebhookIngressProps"
|
|
9548
|
+
}
|
|
9549
|
+
}
|
|
9550
|
+
]
|
|
9551
|
+
},
|
|
9552
|
+
"kind": "class",
|
|
9553
|
+
"locationInModule": {
|
|
9554
|
+
"filename": "src/crew-webhook-ingress.ts",
|
|
9555
|
+
"line": 112
|
|
9556
|
+
},
|
|
9557
|
+
"name": "CrewWebhookIngress",
|
|
9558
|
+
"properties": [
|
|
9559
|
+
{
|
|
9560
|
+
"docs": {
|
|
9561
|
+
"stability": "stable",
|
|
9562
|
+
"summary": "The in-VPC ingress Lambda."
|
|
9563
|
+
},
|
|
9564
|
+
"immutable": true,
|
|
9565
|
+
"locationInModule": {
|
|
9566
|
+
"filename": "src/crew-webhook-ingress.ts",
|
|
9567
|
+
"line": 116
|
|
9568
|
+
},
|
|
9569
|
+
"name": "function",
|
|
9570
|
+
"type": {
|
|
9571
|
+
"fqn": "aws-cdk-lib.aws_lambda.Function"
|
|
9572
|
+
}
|
|
9573
|
+
},
|
|
9574
|
+
{
|
|
9575
|
+
"docs": {
|
|
9576
|
+
"stability": "stable",
|
|
9577
|
+
"summary": "The ingress Lambda's security group (the source of the scoped task ingress rule)."
|
|
9578
|
+
},
|
|
9579
|
+
"immutable": true,
|
|
9580
|
+
"locationInModule": {
|
|
9581
|
+
"filename": "src/crew-webhook-ingress.ts",
|
|
9582
|
+
"line": 118
|
|
9583
|
+
},
|
|
9584
|
+
"name": "securityGroup",
|
|
9585
|
+
"type": {
|
|
9586
|
+
"fqn": "aws-cdk-lib.aws_ec2.SecurityGroup"
|
|
9587
|
+
}
|
|
9588
|
+
},
|
|
9589
|
+
{
|
|
9590
|
+
"docs": {
|
|
9591
|
+
"stability": "stable",
|
|
9592
|
+
"summary": "The SNS topic that fans events into the ingress Lambda."
|
|
9593
|
+
},
|
|
9594
|
+
"immutable": true,
|
|
9595
|
+
"locationInModule": {
|
|
9596
|
+
"filename": "src/crew-webhook-ingress.ts",
|
|
9597
|
+
"line": 114
|
|
9598
|
+
},
|
|
9599
|
+
"name": "topic",
|
|
9600
|
+
"type": {
|
|
9601
|
+
"fqn": "aws-cdk-lib.aws_sns.ITopic"
|
|
9602
|
+
}
|
|
9603
|
+
}
|
|
9604
|
+
],
|
|
9605
|
+
"symbolId": "src/crew-webhook-ingress:CrewWebhookIngress"
|
|
9606
|
+
},
|
|
9607
|
+
"@raindancers/raindancers-crew.CrewWebhookIngressProps": {
|
|
9608
|
+
"assembly": "@raindancers/raindancers-crew",
|
|
9609
|
+
"datatype": true,
|
|
9610
|
+
"docs": {
|
|
9611
|
+
"stability": "stable",
|
|
9612
|
+
"summary": "Properties for {@link CrewWebhookIngress}."
|
|
9613
|
+
},
|
|
9614
|
+
"fqn": "@raindancers/raindancers-crew.CrewWebhookIngressProps",
|
|
9615
|
+
"kind": "interface",
|
|
9616
|
+
"locationInModule": {
|
|
9617
|
+
"filename": "src/crew-webhook-ingress.ts",
|
|
9618
|
+
"line": 15
|
|
9619
|
+
},
|
|
9620
|
+
"name": "CrewWebhookIngressProps",
|
|
9621
|
+
"properties": [
|
|
9622
|
+
{
|
|
9623
|
+
"abstract": true,
|
|
9624
|
+
"docs": {
|
|
9625
|
+
"remarks": "The consumer supplies it: this construct\nwires the plumbing (SNS -> in-VPC Lambda -> task private IP) but does not\nship an opinion about how a webhook payload maps to a crew.",
|
|
9626
|
+
"stability": "stable",
|
|
9627
|
+
"summary": "The code the ingress Lambda runs."
|
|
9628
|
+
},
|
|
9629
|
+
"immutable": true,
|
|
9630
|
+
"locationInModule": {
|
|
9631
|
+
"filename": "src/crew-webhook-ingress.ts",
|
|
9632
|
+
"line": 42
|
|
9633
|
+
},
|
|
9634
|
+
"name": "code",
|
|
9635
|
+
"type": {
|
|
9636
|
+
"fqn": "aws-cdk-lib.aws_lambda.Code"
|
|
9637
|
+
}
|
|
9638
|
+
},
|
|
9639
|
+
{
|
|
9640
|
+
"abstract": true,
|
|
9641
|
+
"docs": {
|
|
9642
|
+
"remarks": "The task security group is\ngranted a scoped inbound rule from this ingress Lambda's SG on the crew\nport only — the one controlled inbound exception to the egress-only model.",
|
|
9643
|
+
"stability": "stable",
|
|
9644
|
+
"summary": "The crew host whose tasks receive webhooks."
|
|
9645
|
+
},
|
|
9646
|
+
"immutable": true,
|
|
9647
|
+
"locationInModule": {
|
|
9648
|
+
"filename": "src/crew-webhook-ingress.ts",
|
|
9649
|
+
"line": 28
|
|
9650
|
+
},
|
|
9651
|
+
"name": "host",
|
|
9652
|
+
"type": {
|
|
9653
|
+
"fqn": "@raindancers/raindancers-crew.EcsCrewHost"
|
|
9654
|
+
}
|
|
9655
|
+
},
|
|
9656
|
+
{
|
|
9657
|
+
"abstract": true,
|
|
9658
|
+
"docs": {
|
|
9659
|
+
"remarks": "The ingress Lambda runs consumer-triggered code, so it carries a boundary\nmatching the rest of the construct.",
|
|
9660
|
+
"stability": "stable",
|
|
9661
|
+
"summary": "ARN of an IAM permissions boundary applied to the Lambda's execution role."
|
|
9662
|
+
},
|
|
9663
|
+
"immutable": true,
|
|
9664
|
+
"locationInModule": {
|
|
9665
|
+
"filename": "src/crew-webhook-ingress.ts",
|
|
9666
|
+
"line": 35
|
|
9667
|
+
},
|
|
9668
|
+
"name": "permissionsBoundaryArn",
|
|
9669
|
+
"type": {
|
|
9670
|
+
"primitive": "string"
|
|
9671
|
+
}
|
|
9672
|
+
},
|
|
9673
|
+
{
|
|
9674
|
+
"abstract": true,
|
|
9675
|
+
"docs": {
|
|
9676
|
+
"remarks": "Must be the same VPC as the crew tasks\nso the Lambda can reach a task's private ENI IP directly with NO VPC\nendpoint.",
|
|
9677
|
+
"stability": "stable",
|
|
9678
|
+
"summary": "VPC to place the ingress Lambda in."
|
|
9679
|
+
},
|
|
9680
|
+
"immutable": true,
|
|
9681
|
+
"locationInModule": {
|
|
9682
|
+
"filename": "src/crew-webhook-ingress.ts",
|
|
9683
|
+
"line": 21
|
|
9684
|
+
},
|
|
9685
|
+
"name": "vpc",
|
|
9686
|
+
"type": {
|
|
9687
|
+
"fqn": "aws-cdk-lib.aws_ec2.IVpc"
|
|
9688
|
+
}
|
|
9689
|
+
},
|
|
9690
|
+
{
|
|
9691
|
+
"abstract": true,
|
|
9692
|
+
"docs": {
|
|
9693
|
+
"default": "lambda.Architecture.ARM_64",
|
|
9694
|
+
"remarks": "Defaults to arm64 to match the Graviton host.",
|
|
9695
|
+
"stability": "stable",
|
|
9696
|
+
"summary": "Lambda architecture."
|
|
9697
|
+
},
|
|
9698
|
+
"immutable": true,
|
|
9699
|
+
"locationInModule": {
|
|
9700
|
+
"filename": "src/crew-webhook-ingress.ts",
|
|
9701
|
+
"line": 64
|
|
9702
|
+
},
|
|
9703
|
+
"name": "architecture",
|
|
9704
|
+
"optional": true,
|
|
9705
|
+
"type": {
|
|
9706
|
+
"fqn": "aws-cdk-lib.aws_lambda.Architecture"
|
|
9707
|
+
}
|
|
9708
|
+
},
|
|
9709
|
+
{
|
|
9710
|
+
"abstract": true,
|
|
9711
|
+
"docs": {
|
|
9712
|
+
"default": "5476",
|
|
9713
|
+
"stability": "stable",
|
|
9714
|
+
"summary": "TCP port on the crew task the Lambda reaches (the gateway/webhook port)."
|
|
9715
|
+
},
|
|
9716
|
+
"immutable": true,
|
|
9717
|
+
"locationInModule": {
|
|
9718
|
+
"filename": "src/crew-webhook-ingress.ts",
|
|
9719
|
+
"line": 79
|
|
9720
|
+
},
|
|
9721
|
+
"name": "crewPort",
|
|
9722
|
+
"optional": true,
|
|
9723
|
+
"type": {
|
|
9724
|
+
"primitive": "number"
|
|
9725
|
+
}
|
|
9726
|
+
},
|
|
9727
|
+
{
|
|
9728
|
+
"abstract": true,
|
|
9729
|
+
"docs": {
|
|
9730
|
+
"default": "'index.handler'",
|
|
9731
|
+
"stability": "stable",
|
|
9732
|
+
"summary": "The Lambda handler entry point."
|
|
9733
|
+
},
|
|
9734
|
+
"immutable": true,
|
|
9735
|
+
"locationInModule": {
|
|
9736
|
+
"filename": "src/crew-webhook-ingress.ts",
|
|
9737
|
+
"line": 49
|
|
9738
|
+
},
|
|
9739
|
+
"name": "handler",
|
|
9740
|
+
"optional": true,
|
|
9741
|
+
"type": {
|
|
9742
|
+
"primitive": "string"
|
|
9743
|
+
}
|
|
9744
|
+
},
|
|
9745
|
+
{
|
|
9746
|
+
"abstract": true,
|
|
9747
|
+
"docs": {
|
|
9748
|
+
"default": "lambda.Runtime.NODEJS_20_X",
|
|
9749
|
+
"remarks": "Must be an arm64-compatible runtime to match the\narm64 default host.",
|
|
9750
|
+
"stability": "stable",
|
|
9751
|
+
"summary": "The Lambda runtime."
|
|
9752
|
+
},
|
|
9753
|
+
"immutable": true,
|
|
9754
|
+
"locationInModule": {
|
|
9755
|
+
"filename": "src/crew-webhook-ingress.ts",
|
|
9756
|
+
"line": 57
|
|
9757
|
+
},
|
|
9758
|
+
"name": "runtime",
|
|
9759
|
+
"optional": true,
|
|
9760
|
+
"type": {
|
|
9761
|
+
"fqn": "aws-cdk-lib.aws_lambda.Runtime"
|
|
9762
|
+
}
|
|
9763
|
+
},
|
|
9764
|
+
{
|
|
9765
|
+
"abstract": true,
|
|
9766
|
+
"docs": {
|
|
9767
|
+
"default": "Duration.seconds(30)",
|
|
9768
|
+
"stability": "stable",
|
|
9769
|
+
"summary": "Lambda timeout."
|
|
9770
|
+
},
|
|
9771
|
+
"immutable": true,
|
|
9772
|
+
"locationInModule": {
|
|
9773
|
+
"filename": "src/crew-webhook-ingress.ts",
|
|
9774
|
+
"line": 93
|
|
9775
|
+
},
|
|
9776
|
+
"name": "timeout",
|
|
9777
|
+
"optional": true,
|
|
9778
|
+
"type": {
|
|
9779
|
+
"fqn": "aws-cdk-lib.Duration"
|
|
9780
|
+
}
|
|
9781
|
+
},
|
|
9782
|
+
{
|
|
9783
|
+
"abstract": true,
|
|
9784
|
+
"docs": {
|
|
9785
|
+
"default": "- a new topic is created",
|
|
9786
|
+
"remarks": "Omit to create one.",
|
|
9787
|
+
"stability": "stable",
|
|
9788
|
+
"summary": "An existing SNS topic to subscribe the Lambda to."
|
|
9789
|
+
},
|
|
9790
|
+
"immutable": true,
|
|
9791
|
+
"locationInModule": {
|
|
9792
|
+
"filename": "src/crew-webhook-ingress.ts",
|
|
9793
|
+
"line": 86
|
|
9794
|
+
},
|
|
9795
|
+
"name": "topic",
|
|
9796
|
+
"optional": true,
|
|
9797
|
+
"type": {
|
|
9798
|
+
"fqn": "aws-cdk-lib.aws_sns.ITopic"
|
|
9799
|
+
}
|
|
9800
|
+
},
|
|
9801
|
+
{
|
|
9802
|
+
"abstract": true,
|
|
9803
|
+
"docs": {
|
|
9804
|
+
"default": "- the VPC's private-with-egress subnets",
|
|
9805
|
+
"remarks": "Should be the same private\nsubnet the crew tasks run in so the Lambda reaches task IPs directly.",
|
|
9806
|
+
"stability": "stable",
|
|
9807
|
+
"summary": "Subnets to place the ingress Lambda's ENIs in."
|
|
9808
|
+
},
|
|
9809
|
+
"immutable": true,
|
|
9810
|
+
"locationInModule": {
|
|
9811
|
+
"filename": "src/crew-webhook-ingress.ts",
|
|
9812
|
+
"line": 72
|
|
9813
|
+
},
|
|
9814
|
+
"name": "vpcSubnets",
|
|
9815
|
+
"optional": true,
|
|
9816
|
+
"type": {
|
|
9817
|
+
"fqn": "aws-cdk-lib.aws_ec2.SubnetSelection"
|
|
9818
|
+
}
|
|
9819
|
+
}
|
|
9820
|
+
],
|
|
9821
|
+
"symbolId": "src/crew-webhook-ingress:CrewWebhookIngressProps"
|
|
9822
|
+
},
|
|
9823
|
+
"@raindancers/raindancers-crew.EcsCrewHost": {
|
|
9824
|
+
"assembly": "@raindancers/raindancers-crew",
|
|
9825
|
+
"base": "constructs.Construct",
|
|
9826
|
+
"docs": {
|
|
9827
|
+
"remarks": "The host registers to the {@link FargateCrewBase} cluster and does the NAT\nfor the crew tasks itself, so the tasks stay fully private with no public\nIPs and no NAT Gateway, fck-nat, VPC endpoints, or ALB. Each task runs in\nawsvpc mode with its own ENI and private VPC IP; each crew keeps its durable\n`~/.kiro/crew` state on its own encrypted EBS volume that survives instance\nreplacement.\n\nIsolation is container-level (shared kernel), accepted as sufficient:\nGraviton Nitro protects the box from other AWS tenants, containers cover\ncrew-to-crew separation. See the host-OOM caution: hard per-task memory caps\nbound each crew's ceiling but a busy crew can still pressure siblings when\nthe sum of actual usage exceeds physical RAM.\n\n`crewCount` defaults to 1, identical to the single-crew shape, so a plain\ninstantiation with no new props gains no extra resources.",
|
|
9828
|
+
"stability": "stable",
|
|
9829
|
+
"summary": "One self-provisioned EC2 host running the ECS agent, hosting `crewCount` Kiro Crew instances as ECS-on-EC2 container tasks."
|
|
9830
|
+
},
|
|
9831
|
+
"fqn": "@raindancers/raindancers-crew.EcsCrewHost",
|
|
9832
|
+
"initializer": {
|
|
9833
|
+
"docs": {
|
|
9834
|
+
"stability": "stable"
|
|
9835
|
+
},
|
|
9836
|
+
"locationInModule": {
|
|
9837
|
+
"filename": "src/ecs-crew-host.ts",
|
|
9838
|
+
"line": 281
|
|
9839
|
+
},
|
|
9840
|
+
"parameters": [
|
|
9841
|
+
{
|
|
9842
|
+
"name": "scope",
|
|
9843
|
+
"type": {
|
|
9844
|
+
"fqn": "constructs.Construct"
|
|
9845
|
+
}
|
|
9846
|
+
},
|
|
9847
|
+
{
|
|
9848
|
+
"name": "id",
|
|
9849
|
+
"type": {
|
|
9850
|
+
"primitive": "string"
|
|
9851
|
+
}
|
|
9852
|
+
},
|
|
9853
|
+
{
|
|
9854
|
+
"name": "props",
|
|
9855
|
+
"type": {
|
|
9856
|
+
"fqn": "@raindancers/raindancers-crew.EcsCrewHostProps"
|
|
9857
|
+
}
|
|
9858
|
+
}
|
|
9859
|
+
]
|
|
9860
|
+
},
|
|
9861
|
+
"kind": "class",
|
|
9862
|
+
"locationInModule": {
|
|
9863
|
+
"filename": "src/ecs-crew-host.ts",
|
|
9864
|
+
"line": 259
|
|
9865
|
+
},
|
|
9866
|
+
"name": "EcsCrewHost",
|
|
9867
|
+
"properties": [
|
|
9868
|
+
{
|
|
9869
|
+
"docs": {
|
|
9870
|
+
"stability": "stable",
|
|
9871
|
+
"summary": "The size-1 Auto Scaling Group holding the single ECS-registered EC2 host."
|
|
9872
|
+
},
|
|
9873
|
+
"immutable": true,
|
|
9874
|
+
"locationInModule": {
|
|
9875
|
+
"filename": "src/ecs-crew-host.ts",
|
|
9876
|
+
"line": 263
|
|
9877
|
+
},
|
|
9878
|
+
"name": "autoScalingGroup",
|
|
9879
|
+
"type": {
|
|
9880
|
+
"fqn": "aws-cdk-lib.aws_autoscaling.AutoScalingGroup"
|
|
9881
|
+
}
|
|
9882
|
+
},
|
|
9883
|
+
{
|
|
9884
|
+
"docs": {
|
|
9885
|
+
"stability": "stable",
|
|
9886
|
+
"summary": "The shared ECS scaffolding (cluster + egress-only task SG)."
|
|
9887
|
+
},
|
|
9888
|
+
"immutable": true,
|
|
9889
|
+
"locationInModule": {
|
|
9890
|
+
"filename": "src/ecs-crew-host.ts",
|
|
9891
|
+
"line": 261
|
|
9892
|
+
},
|
|
9893
|
+
"name": "base",
|
|
9894
|
+
"type": {
|
|
9895
|
+
"fqn": "@raindancers/raindancers-crew.FargateCrewBase"
|
|
9896
|
+
}
|
|
9897
|
+
},
|
|
9898
|
+
{
|
|
9899
|
+
"docs": {
|
|
9900
|
+
"stability": "stable",
|
|
9901
|
+
"summary": "The capacity provider registering the host with the cluster."
|
|
9902
|
+
},
|
|
9903
|
+
"immutable": true,
|
|
9904
|
+
"locationInModule": {
|
|
9905
|
+
"filename": "src/ecs-crew-host.ts",
|
|
9906
|
+
"line": 265
|
|
9907
|
+
},
|
|
9908
|
+
"name": "capacityProvider",
|
|
9909
|
+
"type": {
|
|
9910
|
+
"fqn": "aws-cdk-lib.aws_ecs.AsgCapacityProvider"
|
|
9911
|
+
}
|
|
9912
|
+
},
|
|
9913
|
+
{
|
|
9914
|
+
"docs": {
|
|
9915
|
+
"stability": "stable",
|
|
9916
|
+
"summary": "The resolved crew names."
|
|
9917
|
+
},
|
|
9918
|
+
"immutable": true,
|
|
9919
|
+
"locationInModule": {
|
|
9920
|
+
"filename": "src/ecs-crew-host.ts",
|
|
9921
|
+
"line": 279
|
|
9922
|
+
},
|
|
9923
|
+
"name": "crewNames",
|
|
9924
|
+
"type": {
|
|
9925
|
+
"collection": {
|
|
9926
|
+
"elementtype": {
|
|
9927
|
+
"primitive": "string"
|
|
9928
|
+
},
|
|
9929
|
+
"kind": "array"
|
|
9930
|
+
}
|
|
9931
|
+
}
|
|
9932
|
+
},
|
|
9933
|
+
{
|
|
9934
|
+
"docs": {
|
|
9935
|
+
"stability": "stable",
|
|
9936
|
+
"summary": "The per-crew scaffolding (roles + log group), one per crew."
|
|
9937
|
+
},
|
|
9938
|
+
"immutable": true,
|
|
9939
|
+
"locationInModule": {
|
|
9940
|
+
"filename": "src/ecs-crew-host.ts",
|
|
9941
|
+
"line": 271
|
|
9942
|
+
},
|
|
9943
|
+
"name": "crews",
|
|
9944
|
+
"type": {
|
|
9945
|
+
"collection": {
|
|
9946
|
+
"elementtype": {
|
|
9947
|
+
"fqn": "@raindancers/raindancers-crew.FargateCrew"
|
|
9948
|
+
},
|
|
9949
|
+
"kind": "array"
|
|
9950
|
+
}
|
|
9951
|
+
}
|
|
9952
|
+
},
|
|
9953
|
+
{
|
|
9954
|
+
"docs": {
|
|
9955
|
+
"stability": "stable",
|
|
9956
|
+
"summary": "The per-crew durable data volumes (device/label/mount metadata)."
|
|
9957
|
+
},
|
|
9958
|
+
"immutable": true,
|
|
9959
|
+
"locationInModule": {
|
|
9960
|
+
"filename": "src/ecs-crew-host.ts",
|
|
9961
|
+
"line": 275
|
|
9962
|
+
},
|
|
9963
|
+
"name": "dataVolumes",
|
|
9964
|
+
"type": {
|
|
9965
|
+
"collection": {
|
|
9966
|
+
"elementtype": {
|
|
9967
|
+
"fqn": "@raindancers/raindancers-crew.CrewDataVolume"
|
|
9968
|
+
},
|
|
9969
|
+
"kind": "array"
|
|
9970
|
+
}
|
|
9971
|
+
}
|
|
9972
|
+
},
|
|
9973
|
+
{
|
|
9974
|
+
"docs": {
|
|
9975
|
+
"stability": "stable",
|
|
9976
|
+
"summary": "The host's SSM-only security group (no inbound)."
|
|
9977
|
+
},
|
|
9978
|
+
"immutable": true,
|
|
9979
|
+
"locationInModule": {
|
|
9980
|
+
"filename": "src/ecs-crew-host.ts",
|
|
9981
|
+
"line": 269
|
|
9982
|
+
},
|
|
9983
|
+
"name": "hostSecurityGroup",
|
|
9984
|
+
"type": {
|
|
9985
|
+
"fqn": "aws-cdk-lib.aws_ec2.SecurityGroup"
|
|
9986
|
+
}
|
|
9987
|
+
},
|
|
9988
|
+
{
|
|
9989
|
+
"docs": {
|
|
9990
|
+
"stability": "stable",
|
|
9991
|
+
"summary": "The region the host runs in (read from the stack env, never a prop)."
|
|
9992
|
+
},
|
|
9993
|
+
"immutable": true,
|
|
9994
|
+
"locationInModule": {
|
|
9995
|
+
"filename": "src/ecs-crew-host.ts",
|
|
9996
|
+
"line": 574
|
|
9997
|
+
},
|
|
9998
|
+
"name": "region",
|
|
9999
|
+
"type": {
|
|
10000
|
+
"primitive": "string"
|
|
10001
|
+
}
|
|
10002
|
+
},
|
|
10003
|
+
{
|
|
10004
|
+
"docs": {
|
|
10005
|
+
"stability": "stable",
|
|
10006
|
+
"summary": "The host instance's IAM role (carries the permissions boundary)."
|
|
10007
|
+
},
|
|
10008
|
+
"immutable": true,
|
|
10009
|
+
"locationInModule": {
|
|
10010
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10011
|
+
"line": 267
|
|
10012
|
+
},
|
|
10013
|
+
"name": "role",
|
|
10014
|
+
"type": {
|
|
10015
|
+
"fqn": "aws-cdk-lib.aws_iam.Role"
|
|
10016
|
+
}
|
|
10017
|
+
},
|
|
10018
|
+
{
|
|
10019
|
+
"docs": {
|
|
10020
|
+
"stability": "stable",
|
|
10021
|
+
"summary": "The per-crew EC2 services."
|
|
10022
|
+
},
|
|
10023
|
+
"immutable": true,
|
|
10024
|
+
"locationInModule": {
|
|
10025
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10026
|
+
"line": 273
|
|
10027
|
+
},
|
|
10028
|
+
"name": "services",
|
|
10029
|
+
"type": {
|
|
10030
|
+
"collection": {
|
|
10031
|
+
"elementtype": {
|
|
10032
|
+
"fqn": "aws-cdk-lib.aws_ecs.Ec2Service"
|
|
10033
|
+
},
|
|
10034
|
+
"kind": "array"
|
|
10035
|
+
}
|
|
10036
|
+
}
|
|
10037
|
+
},
|
|
10038
|
+
{
|
|
10039
|
+
"docs": {
|
|
10040
|
+
"stability": "stable",
|
|
10041
|
+
"summary": "The discovery tag value written as `kirocrew:ecs-host`."
|
|
10042
|
+
},
|
|
10043
|
+
"immutable": true,
|
|
10044
|
+
"locationInModule": {
|
|
10045
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10046
|
+
"line": 277
|
|
10047
|
+
},
|
|
10048
|
+
"name": "stackTag",
|
|
10049
|
+
"type": {
|
|
10050
|
+
"primitive": "string"
|
|
10051
|
+
}
|
|
10052
|
+
}
|
|
10053
|
+
],
|
|
10054
|
+
"symbolId": "src/ecs-crew-host:EcsCrewHost"
|
|
10055
|
+
},
|
|
10056
|
+
"@raindancers/raindancers-crew.EcsCrewHostProps": {
|
|
10057
|
+
"assembly": "@raindancers/raindancers-crew",
|
|
10058
|
+
"datatype": true,
|
|
10059
|
+
"docs": {
|
|
10060
|
+
"stability": "stable",
|
|
10061
|
+
"summary": "Properties for {@link EcsCrewHost}."
|
|
10062
|
+
},
|
|
10063
|
+
"fqn": "@raindancers/raindancers-crew.EcsCrewHostProps",
|
|
10064
|
+
"kind": "interface",
|
|
10065
|
+
"locationInModule": {
|
|
10066
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10067
|
+
"line": 46
|
|
10068
|
+
},
|
|
10069
|
+
"name": "EcsCrewHostProps",
|
|
10070
|
+
"properties": [
|
|
10071
|
+
{
|
|
10072
|
+
"abstract": true,
|
|
10073
|
+
"docs": {
|
|
10074
|
+
"remarks": "The host runs a prompt-injectable agent per crew, so its role MUST carry a\nboundary that caps blast radius. Required, not optional, matching\n{@link RemoteCrewInstanceProps.permissionsBoundaryArn }. Any valid managed-\npolicy ARN is accepted here (this is the EC2/host boundary).\n\nThe per-crew task/execution roles take {@link crewPermissionsBoundaryArn},\nwhich is validated separately against the `kirocrew-crew-boundary` pattern\nthe crew roles require.",
|
|
10075
|
+
"stability": "stable",
|
|
10076
|
+
"summary": "ARN of an IAM permissions boundary applied to the host instance role."
|
|
10077
|
+
},
|
|
10078
|
+
"immutable": true,
|
|
10079
|
+
"locationInModule": {
|
|
10080
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10081
|
+
"line": 69
|
|
10082
|
+
},
|
|
10083
|
+
"name": "permissionsBoundaryArn",
|
|
10084
|
+
"type": {
|
|
10085
|
+
"primitive": "string"
|
|
10086
|
+
}
|
|
10087
|
+
},
|
|
10088
|
+
{
|
|
10089
|
+
"abstract": true,
|
|
10090
|
+
"docs": {
|
|
10091
|
+
"remarks": "The construct consumes a two-subnet host-NAT topology it does not build:\none PUBLIC subnet (host ENI + Elastic IP + IGW route) and one PRIVATE\nsubnet (task ENIs, `0.0.0.0/0` -> the host ENI, no IGW route). Select them\nwith {@link hostSubnets} and {@link taskSubnets}.",
|
|
10092
|
+
"stability": "stable",
|
|
10093
|
+
"summary": "VPC to run in. Passed in, never created here."
|
|
10094
|
+
},
|
|
10095
|
+
"immutable": true,
|
|
10096
|
+
"locationInModule": {
|
|
10097
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10098
|
+
"line": 55
|
|
10099
|
+
},
|
|
10100
|
+
"name": "vpc",
|
|
10101
|
+
"type": {
|
|
10102
|
+
"fqn": "aws-cdk-lib.aws_ec2.IVpc"
|
|
10103
|
+
}
|
|
10104
|
+
},
|
|
10105
|
+
{
|
|
10106
|
+
"abstract": true,
|
|
10107
|
+
"docs": {
|
|
10108
|
+
"default": "CrewArchitecture.ARM64",
|
|
10109
|
+
"remarks": "Must match\n{@link instanceType} when that is set.",
|
|
10110
|
+
"stability": "stable",
|
|
10111
|
+
"summary": "CPU architecture of the host and the crew container images."
|
|
10112
|
+
},
|
|
10113
|
+
"immutable": true,
|
|
10114
|
+
"locationInModule": {
|
|
10115
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10116
|
+
"line": 103
|
|
10117
|
+
},
|
|
10118
|
+
"name": "architecture",
|
|
10119
|
+
"optional": true,
|
|
10120
|
+
"type": {
|
|
10121
|
+
"fqn": "@raindancers/raindancers-crew.CrewArchitecture"
|
|
10122
|
+
}
|
|
10123
|
+
},
|
|
10124
|
+
{
|
|
10125
|
+
"abstract": true,
|
|
10126
|
+
"docs": {
|
|
10127
|
+
"default": "- no off-box backup",
|
|
10128
|
+
"remarks": "When set, each per-crew TASK role is granted write so\nthe running container pushes its own snapshots off-box.",
|
|
10129
|
+
"stability": "stable",
|
|
10130
|
+
"summary": "An S3 backup bucket."
|
|
10131
|
+
},
|
|
10132
|
+
"immutable": true,
|
|
10133
|
+
"locationInModule": {
|
|
10134
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10135
|
+
"line": 228
|
|
10136
|
+
},
|
|
10137
|
+
"name": "backupBucket",
|
|
10138
|
+
"optional": true,
|
|
10139
|
+
"type": {
|
|
10140
|
+
"fqn": "@raindancers/raindancers-crew.ICrewBackupBucket"
|
|
10141
|
+
}
|
|
10142
|
+
},
|
|
10143
|
+
{
|
|
10144
|
+
"abstract": true,
|
|
10145
|
+
"docs": {
|
|
10146
|
+
"default": "1",
|
|
10147
|
+
"remarks": "DEFAULT 1 — identical to today's single-crew behaviour, so existing\nconsumers gain nothing new. The 55minutes consumer passes 3. Validated\n1..8: awsvpc gives each task its own ENI, and (crewCount + 1) ENIs (the\nhost ENI plus one per task) must fit the instance type's ENI budget.",
|
|
10148
|
+
"stability": "stable",
|
|
10149
|
+
"summary": "Number of Kiro Crew instances to host, each one ECS task/service."
|
|
10150
|
+
},
|
|
10151
|
+
"immutable": true,
|
|
10152
|
+
"locationInModule": {
|
|
10153
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10154
|
+
"line": 115
|
|
10155
|
+
},
|
|
10156
|
+
"name": "crewCount",
|
|
10157
|
+
"optional": true,
|
|
10158
|
+
"type": {
|
|
10159
|
+
"primitive": "number"
|
|
10160
|
+
}
|
|
10161
|
+
},
|
|
10162
|
+
{
|
|
10163
|
+
"abstract": true,
|
|
10164
|
+
"docs": {
|
|
10165
|
+
"default": "- unset (shared CPU)",
|
|
10166
|
+
"remarks": "Omit to\nleave CPU unconstrained (crews share the host CPU fairly under contention).",
|
|
10167
|
+
"stability": "stable",
|
|
10168
|
+
"summary": "Optional SOFT CPU shares per crew container (1024 = one vCPU)."
|
|
10169
|
+
},
|
|
10170
|
+
"immutable": true,
|
|
10171
|
+
"locationInModule": {
|
|
10172
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10173
|
+
"line": 194
|
|
10174
|
+
},
|
|
10175
|
+
"name": "crewCpuShares",
|
|
10176
|
+
"optional": true,
|
|
10177
|
+
"type": {
|
|
10178
|
+
"primitive": "number"
|
|
10179
|
+
}
|
|
10180
|
+
},
|
|
10181
|
+
{
|
|
10182
|
+
"abstract": true,
|
|
10183
|
+
"docs": {
|
|
10184
|
+
"default": "20",
|
|
10185
|
+
"remarks": "Always encrypted, always\n`deleteOnTermination: false` (a crew's `~/.kiro/crew` learnings must\noutlive an instance replacement, matching the CrewBackupBucket RETAIN\nintent).",
|
|
10186
|
+
"stability": "stable",
|
|
10187
|
+
"summary": "Per-crew durable EBS data volume size in GiB."
|
|
10188
|
+
},
|
|
10189
|
+
"immutable": true,
|
|
10190
|
+
"locationInModule": {
|
|
10191
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10192
|
+
"line": 160
|
|
10193
|
+
},
|
|
10194
|
+
"name": "crewDataVolumeSizeGb",
|
|
10195
|
+
"optional": true,
|
|
10196
|
+
"type": {
|
|
10197
|
+
"primitive": "number"
|
|
10198
|
+
}
|
|
10199
|
+
},
|
|
10200
|
+
{
|
|
10201
|
+
"abstract": true,
|
|
10202
|
+
"docs": {
|
|
10203
|
+
"default": "ec2.EbsDeviceVolumeType.GP3",
|
|
10204
|
+
"stability": "stable",
|
|
10205
|
+
"summary": "Per-crew EBS volume type."
|
|
10206
|
+
},
|
|
10207
|
+
"immutable": true,
|
|
10208
|
+
"locationInModule": {
|
|
10209
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10210
|
+
"line": 167
|
|
10211
|
+
},
|
|
10212
|
+
"name": "crewDataVolumeType",
|
|
10213
|
+
"optional": true,
|
|
10214
|
+
"type": {
|
|
10215
|
+
"fqn": "aws-cdk-lib.aws_ec2.EbsDeviceVolumeType"
|
|
10216
|
+
}
|
|
10217
|
+
},
|
|
10218
|
+
{
|
|
10219
|
+
"abstract": true,
|
|
10220
|
+
"docs": {
|
|
10221
|
+
"default": "'public.ecr.aws/kirocrew/crew:latest'",
|
|
10222
|
+
"remarks": "When {@link ecrRepositoryArn}\nis set this is typically the repo URI with a tag; otherwise a public\nregistry reference.",
|
|
10223
|
+
"stability": "stable",
|
|
10224
|
+
"summary": "Container image reference for the crew task."
|
|
10225
|
+
},
|
|
10226
|
+
"immutable": true,
|
|
10227
|
+
"locationInModule": {
|
|
10228
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10229
|
+
"line": 212
|
|
10230
|
+
},
|
|
10231
|
+
"name": "crewImage",
|
|
10232
|
+
"optional": true,
|
|
10233
|
+
"type": {
|
|
10234
|
+
"primitive": "string"
|
|
10235
|
+
}
|
|
10236
|
+
},
|
|
10237
|
+
{
|
|
10238
|
+
"abstract": true,
|
|
10239
|
+
"docs": {
|
|
10240
|
+
"default": "2048",
|
|
10241
|
+
"remarks": "A crew is OOM-killed at this\nceiling, so no single crew can consume the whole host. Set the SUM of hard\ncaps at or below (physical RAM minus host + ECS-agent headroom) for a hard\ncross-crew guarantee — see the host-OOM caution in the README.",
|
|
10242
|
+
"stability": "stable",
|
|
10243
|
+
"summary": "HARD memory cap (MiB) per crew container."
|
|
10244
|
+
},
|
|
10245
|
+
"immutable": true,
|
|
10246
|
+
"locationInModule": {
|
|
10247
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10248
|
+
"line": 186
|
|
10249
|
+
},
|
|
10250
|
+
"name": "crewMemoryHardLimitMiB",
|
|
10251
|
+
"optional": true,
|
|
10252
|
+
"type": {
|
|
10253
|
+
"primitive": "number"
|
|
10254
|
+
}
|
|
10255
|
+
},
|
|
10256
|
+
{
|
|
10257
|
+
"abstract": true,
|
|
10258
|
+
"docs": {
|
|
10259
|
+
"default": "1024",
|
|
10260
|
+
"remarks": "ECS uses it for\nplacement; a crew may burst above it when the host has spare RAM, so idle\ncrews cost little.",
|
|
10261
|
+
"stability": "stable",
|
|
10262
|
+
"summary": "SOFT memory reservation (MiB) per crew container."
|
|
10263
|
+
},
|
|
10264
|
+
"immutable": true,
|
|
10265
|
+
"locationInModule": {
|
|
10266
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10267
|
+
"line": 176
|
|
10268
|
+
},
|
|
10269
|
+
"name": "crewMemoryReservationMiB",
|
|
10270
|
+
"optional": true,
|
|
10271
|
+
"type": {
|
|
10272
|
+
"primitive": "number"
|
|
10273
|
+
}
|
|
10274
|
+
},
|
|
10275
|
+
{
|
|
10276
|
+
"abstract": true,
|
|
10277
|
+
"docs": {
|
|
10278
|
+
"default": "- no crew boundary (declared degraded mode; see FargateCrew)",
|
|
10279
|
+
"remarks": "Separate from {@link permissionsBoundaryArn} because the crew roles enforce\nthe `kirocrew-crew-boundary` policy name (a different boundary from the\nhost's), and validating them together would force one ARN to satisfy two\ndistinct patterns. Optional, mirroring {@link FargateCrew}'s declared\ndegraded mode: omit it only when no crew-boundary creator exists yet.",
|
|
10280
|
+
"stability": "stable",
|
|
10281
|
+
"summary": "ARN of the pre-created shared crew permissions boundary (`arn:aws:iam::<account>:policy/kirocrew-crew-boundary`), applied to every per-crew task and execution role."
|
|
10282
|
+
},
|
|
10283
|
+
"immutable": true,
|
|
10284
|
+
"locationInModule": {
|
|
10285
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10286
|
+
"line": 84
|
|
10287
|
+
},
|
|
10288
|
+
"name": "crewPermissionsBoundaryArn",
|
|
10289
|
+
"optional": true,
|
|
10290
|
+
"type": {
|
|
10291
|
+
"primitive": "string"
|
|
10292
|
+
}
|
|
10293
|
+
},
|
|
10294
|
+
{
|
|
10295
|
+
"abstract": true,
|
|
10296
|
+
"docs": {
|
|
10297
|
+
"default": "- crew-1 .. crew-<crewCount>",
|
|
10298
|
+
"remarks": "Each must match the {@link FargateCrew} regex\n`^[a-z0-9]([a-z0-9-]{0,30}[a-z0-9])?$`; the log group, roles, and secret\nnamespace are derived from it. When omitted, names are generated as\n`crew-1`..`crew-<crewCount>`. When set, the list length must equal\n{@link crewCount}.",
|
|
10299
|
+
"stability": "stable",
|
|
10300
|
+
"summary": "Explicit crew names."
|
|
10301
|
+
},
|
|
10302
|
+
"immutable": true,
|
|
10303
|
+
"locationInModule": {
|
|
10304
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10305
|
+
"line": 126
|
|
10306
|
+
},
|
|
10307
|
+
"name": "crews",
|
|
10308
|
+
"optional": true,
|
|
10309
|
+
"type": {
|
|
10310
|
+
"collection": {
|
|
10311
|
+
"elementtype": {
|
|
10312
|
+
"primitive": "string"
|
|
10313
|
+
},
|
|
10314
|
+
"kind": "array"
|
|
10315
|
+
}
|
|
10316
|
+
}
|
|
10317
|
+
},
|
|
10318
|
+
{
|
|
10319
|
+
"abstract": true,
|
|
10320
|
+
"docs": {
|
|
10321
|
+
"default": "- public registry; no pull grant",
|
|
10322
|
+
"remarks": "Leave unset when\nthe image is pulled from a public registry. When set, each per-crew\nexecution role gets a pull grant scoped to this one repository.",
|
|
10323
|
+
"stability": "stable",
|
|
10324
|
+
"summary": "ARN of the private ECR repository holding the crew image."
|
|
10325
|
+
},
|
|
10326
|
+
"immutable": true,
|
|
10327
|
+
"locationInModule": {
|
|
10328
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10329
|
+
"line": 203
|
|
10330
|
+
},
|
|
10331
|
+
"name": "ecrRepositoryArn",
|
|
10332
|
+
"optional": true,
|
|
10333
|
+
"type": {
|
|
10334
|
+
"primitive": "string"
|
|
10335
|
+
}
|
|
10336
|
+
},
|
|
10337
|
+
{
|
|
10338
|
+
"abstract": true,
|
|
10339
|
+
"docs": {
|
|
10340
|
+
"default": "- one public subnet in the VPC",
|
|
10341
|
+
"remarks": "This is the PUBLIC subnet (IGW-routed,\ncarries the Elastic IP), because the host does the NAT for the tasks.",
|
|
10342
|
+
"stability": "stable",
|
|
10343
|
+
"summary": "Subnet selection for the host ENI."
|
|
10344
|
+
},
|
|
10345
|
+
"immutable": true,
|
|
10346
|
+
"locationInModule": {
|
|
10347
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10348
|
+
"line": 134
|
|
10349
|
+
},
|
|
10350
|
+
"name": "hostSubnets",
|
|
10351
|
+
"optional": true,
|
|
10352
|
+
"type": {
|
|
10353
|
+
"fqn": "aws-cdk-lib.aws_ec2.SubnetSelection"
|
|
10354
|
+
}
|
|
10355
|
+
},
|
|
10356
|
+
{
|
|
10357
|
+
"abstract": true,
|
|
10358
|
+
"docs": {
|
|
10359
|
+
"default": "- m7g.2xlarge (arm64) / m7i.2xlarge (x86_64), matching\nRemoteCrewInstance",
|
|
10360
|
+
"remarks": "The type STAYS a settable prop: the 55minutes consumer passes\n`new ec2.InstanceType('m9g.xlarge')`. Never hardcoded to one family.",
|
|
10361
|
+
"stability": "stable",
|
|
10362
|
+
"summary": "EC2 instance type for the single ECS-registered host."
|
|
10363
|
+
},
|
|
10364
|
+
"immutable": true,
|
|
10365
|
+
"locationInModule": {
|
|
10366
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10367
|
+
"line": 95
|
|
10368
|
+
},
|
|
10369
|
+
"name": "instanceType",
|
|
10370
|
+
"optional": true,
|
|
10371
|
+
"type": {
|
|
10372
|
+
"fqn": "aws-cdk-lib.aws_ec2.InstanceType"
|
|
10373
|
+
}
|
|
10374
|
+
},
|
|
10375
|
+
{
|
|
10376
|
+
"abstract": true,
|
|
10377
|
+
"docs": {
|
|
10378
|
+
"default": "30",
|
|
10379
|
+
"remarks": "One of the CloudWatch retention values\n(see {@link FargateCrew}).",
|
|
10380
|
+
"stability": "stable",
|
|
10381
|
+
"summary": "Days a crew's task logs are kept."
|
|
10382
|
+
},
|
|
10383
|
+
"immutable": true,
|
|
10384
|
+
"locationInModule": {
|
|
10385
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10386
|
+
"line": 220
|
|
10387
|
+
},
|
|
10388
|
+
"name": "logRetentionDays",
|
|
10389
|
+
"optional": true,
|
|
10390
|
+
"type": {
|
|
10391
|
+
"primitive": "number"
|
|
10392
|
+
}
|
|
10393
|
+
},
|
|
10394
|
+
{
|
|
10395
|
+
"abstract": true,
|
|
10396
|
+
"docs": {
|
|
10397
|
+
"default": "60",
|
|
10398
|
+
"remarks": "Always encrypted.",
|
|
10399
|
+
"stability": "stable",
|
|
10400
|
+
"summary": "gp3 root volume size in GiB for the host."
|
|
10401
|
+
},
|
|
10402
|
+
"immutable": true,
|
|
10403
|
+
"locationInModule": {
|
|
10404
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10405
|
+
"line": 150
|
|
10406
|
+
},
|
|
10407
|
+
"name": "rootVolumeSizeGb",
|
|
10408
|
+
"optional": true,
|
|
10409
|
+
"type": {
|
|
10410
|
+
"primitive": "number"
|
|
10411
|
+
}
|
|
10412
|
+
},
|
|
10413
|
+
{
|
|
10414
|
+
"abstract": true,
|
|
10415
|
+
"docs": {
|
|
10416
|
+
"default": "'kirocrew'",
|
|
10417
|
+
"remarks": "Must match\n`[a-zA-Z0-9-]{1,51}`. The cluster is named `kirocrew-crew-<stackTag>`.",
|
|
10418
|
+
"stability": "stable",
|
|
10419
|
+
"summary": "Discovery tag value written as `kirocrew:ecs-host`."
|
|
10420
|
+
},
|
|
10421
|
+
"immutable": true,
|
|
10422
|
+
"locationInModule": {
|
|
10423
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10424
|
+
"line": 236
|
|
10425
|
+
},
|
|
10426
|
+
"name": "stackTag",
|
|
10427
|
+
"optional": true,
|
|
10428
|
+
"type": {
|
|
10429
|
+
"primitive": "string"
|
|
10430
|
+
}
|
|
10431
|
+
},
|
|
10432
|
+
{
|
|
10433
|
+
"abstract": true,
|
|
10434
|
+
"docs": {
|
|
10435
|
+
"default": "- the VPC's private-with-egress subnets",
|
|
10436
|
+
"remarks": "This is the PRIVATE subnet whose\n`0.0.0.0/0` route points at the host ENI (no IGW route). Tasks get no\npublic IP.",
|
|
10437
|
+
"stability": "stable",
|
|
10438
|
+
"summary": "Subnet selection for the crew task ENIs."
|
|
10439
|
+
},
|
|
10440
|
+
"immutable": true,
|
|
10441
|
+
"locationInModule": {
|
|
10442
|
+
"filename": "src/ecs-crew-host.ts",
|
|
10443
|
+
"line": 143
|
|
10444
|
+
},
|
|
10445
|
+
"name": "taskSubnets",
|
|
10446
|
+
"optional": true,
|
|
10447
|
+
"type": {
|
|
10448
|
+
"fqn": "aws-cdk-lib.aws_ec2.SubnetSelection"
|
|
10449
|
+
}
|
|
10450
|
+
}
|
|
10451
|
+
],
|
|
10452
|
+
"symbolId": "src/ecs-crew-host:EcsCrewHostProps"
|
|
10453
|
+
},
|
|
9431
10454
|
"@raindancers/raindancers-crew.FargateCpuArchitecture": {
|
|
9432
10455
|
"assembly": "@raindancers/raindancers-crew",
|
|
9433
10456
|
"docs": {
|
|
@@ -10547,6 +11570,6 @@
|
|
|
10547
11570
|
"symbolId": "src/remote-crew-instance-props:WebhookIngress"
|
|
10548
11571
|
}
|
|
10549
11572
|
},
|
|
10550
|
-
"version": "0.0.
|
|
10551
|
-
"fingerprint": "
|
|
11573
|
+
"version": "0.0.2",
|
|
11574
|
+
"fingerprint": "jT4lYbBvDKoB3fC/KVbUZT6Zqj04ZkPfUJHktccnGYM="
|
|
10552
11575
|
}
|