AWS host phase 5: Fargate workspaces #82

Merged
jknapp merged 43 commits from feat/aws-fargate-workspaces into main 2026-11-15 21:51:12 +00:00
43 Commits
Author SHA1 Message Date
shadowdaoandClaude Opus 5.5 b80ca0681e docs(aws): record the live re-run of the final idle-stop path
Secret Scan / scan (push) Successful in 10s
Build App (Preview) / compute-version (pull_request) Successful in 7s
Secret Scan / scan (pull_request) Successful in 17s
Build Container / build-container (pull_request) Successful in 4m3s
Build App (Preview) / create-release (pull_request) Successful in 4s
Build App (Preview) / test (pull_request) Successful in 6m19s
Build App (Preview) / build-macos (pull_request) Successful in 5m54s
Build App (Preview) / build-windows (pull_request) Successful in 10m27s
Build App (Preview) / build-linux (pull_request) Successful in 16m45s
Build App (Preview) / prune-previews (pull_request) Successful in 20s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 13:28:39 -08:00
shadowdaoandClaude Opus 5.5 d73a19a9e7 docs: note the stop guard order, background polls, clone skip and trap order
Secret Scan / scan (push) Successful in 18s
Build App (Preview) / compute-version (pull_request) Successful in 5s
Build App (Preview) / test (pull_request) Successful in 6m21s
Secret Scan / scan (pull_request) Successful in 8s
Build App (Preview) / create-release (pull_request) Successful in 1s
Build App (Preview) / build-macos (pull_request) Successful in 5m55s
Build App (Preview) / build-linux (pull_request) Successful in 8m29s
Build App (Preview) / build-windows (pull_request) Successful in 10m36s
Build App (Preview) / prune-previews (pull_request) Successful in 2s
Build Container / build-container (pull_request) Successful in 22m23s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 13:08:05 -08:00
shadowdaoandClaude Opus 5.5 c467308513 fix(aws): keep the access point id when a removal keeps the saved files
remove_aws_resources cleared access_point_id even without discard_data, though the
access point stays; the project could then move hosts and orphan it. The id is
now kept, so a later start reuses it, a later removal with "Also remove the
access point" deletes it, and moving the project is refused until then (the
message and the Host section say so).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 13:08:05 -08:00
shadowdaoandClaude Opus 5.5 be2825d344 fix(aws): the file viewer's change poll no longer counts as workspace activity
Its 2 s sha256sum poll now carries X-Triple-C-Background, so an open viewer does
not keep an idle AWS workspace up. Opening and saving a file stay foreground;
Docker is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 13:08:05 -08:00
shadowdaoandClaude Opus 5.5 33eb63d907 fix(aws): forget a stale stopped mark on a project's unattached target id
The death watch's stopped marks are keyed by target id, and an unattached AWS
project's id (http://unattached.invalid/<id>/) is reused by every later unattached
spell, but only an endpoint URL's mark was ever removed. A stale mark could make
the watch report a live, billed task as stopped. Registering a tunnel now clears
the project's placeholder mark, and reconcile forgets it before asking ECS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 13:08:05 -08:00
shadowdaoandClaude Opus 5.5 884a665e7d fix(aws): close terminals before the stop guard's push and bound it in the container
The guard pushed and recorded `pushed` while terminals (and Claude in them) were
still open; the TERM hook then skipped its push, so later edits were lost. Stop now
closes the project's exec sessions and auth bridge first, then pushes, records the
marker and stops the task. A failed push still aborts the stop with the status
restored; the auth bridge is re-armed and the error says the terminals were closed.

The script also runs under `/usr/bin/timeout -k 5` ending 10 s before the client's
timeout: the agent does not kill an exec its client gave up on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 13:07:54 -08:00
shadowdaoandClaude Opus 5.5 170ba1e94d fix(container): skip repos still cloning, re-check idleness after the idle push, trap TERM before background work
- clone_repos records `<folder>\tcloning` as each clone begins; triple-c-wip-push
  skips a folder whose last state is `cloning` while the clone is not done (dry run
  reports "cloning": true; RepoState/TS carry it, the stop guard lists it as
  "still cloning — nothing to push" and never asks because of it).
- The idle watcher re-checks quiet() after a successful push and goes back to
  watching if someone came back during it.
- The entrypoint installs its stop trap before the idle watcher and the background
  clone start, so a TERM in between still runs aws_before_stop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 13:07:53 -08:00
shadowdaoandClaude Opus 5.5 276f5378a4 fix(aws): give the permission check room for throttled retries and say it can be slow
Secret Scan / scan (push) Successful in 5s
Build App (Preview) / compute-version (pull_request) Successful in 4s
Build App (Preview) / create-release (pull_request) Successful in 2s
Secret Scan / scan (pull_request) Successful in 6s
Build App (Preview) / build-macos (pull_request) Successful in 5m56s
Build App (Preview) / build-linux (pull_request) Successful in 8m42s
Build App (Preview) / build-windows (pull_request) Successful in 10m38s
Build App (Preview) / prune-previews (pull_request) Successful in 3s
Build App (Preview) / test (pull_request) Successful in 22m44s
Build Container / build-container (pull_request) Successful in 25m25s
The connection-wide 30 s operation limit counts retry backoff, so a
throttled SimulatePrincipalPolicy got about six of its ten adaptive
attempts. The IAM client used by the check now has a 120 s operation
limit, and Settings tells the user a check can take a few minutes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 12:54:34 -08:00
shadowdaoandClaude Opus 5.5 3c1c276769 docs(aws): note the idle-stop changes are not yet re-verified live
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 12:37:58 -08:00
shadowdaoandClaude Opus 5.5 8a3c552958 test(aws): the live idle stop holds a terminal open and polls in the background
The idle wait now keeps an attach open (silent) and runs the auth
bridge's background exec every 2 s; the task must still stop itself and
ECS must report it as an idle stop (exit 75 -> StopKind::Idle).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 12:36:23 -08:00
shadowdaoandClaude Opus 5.5 ce020f79a1 fix(aws): the e2e script uses only the named profile and always cleans up
It unsets every caller AWS_* variable (keeping only where the profile's
files are, now documented), sets AWS_PROFILE explicitly, attempts the ECR
delete in the EXIT trap unconditionally (RepositoryNotFound tolerated,
bounded at 120 s), and exits 130/143 on INT/TERM (M21).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 12:35:50 -08:00
shadowdaoandClaude Opus 5.5 24a82bd4c8 fix(aws): warn that Bedrock profile auth can't work in an AWS workspace
The task has no ~/.aws from this machine and SSO can't refresh there;
the note points at static keys or a bearer token (m10). The auth bridge
stays enabled on AWS (its poll is now a background request).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 12:34:34 -08:00
shadowdaoandClaude Opus 5.5 7f113f58ac fix(aws): refuse credentials in repo URLs and HEAD as a branch
- validate_repo_url rejects https URLs with userinfo (user:pass@ or
  token@), pointing at the project's Git HTTPS token setting (m4).
- validate_branch rejects HEAD (m5).
- The FIXED_ENVIRONMENT doc comment sits on FIXED_ENVIRONMENT again (m6).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 12:34:03 -08:00
shadowdaoandClaude Opus 5.5 2772647690 fix(aws): reconcile AWS projects at startup without waiting for Docker
- New reconcile_aws_projects command (handler, capability, TS wrapper)
  that App runs on mount regardless of Docker; reconcile_project_statuses
  now skips AWS projects. Projects reconcile concurrently, 4 at a time,
  each still bounded at 15 s.
- reconcile_task falls back to find_project_task when the stored task is
  gone or stopped, before calling the project Gone (m3).
- An AWS project with no registered tunnel gets a placeholder target id
  (http://unattached.invalid/<id>/) instead of the last run's loopback
  URL, so a reused port can't match the wrong project; the death watch
  still reports it by that id until a re-attach registers (m9).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 12:33:22 -08:00
shadowdaoandClaude Opus 5.5 5e8e67a0a4 fix(aws): say why a task stopped, and bound every AWS call
- classify_stop is wired into the death watch: stopped_among returns
  each task's StopKind, the tunnel registry keeps it, and ContainerExited
  carries a StopNote. Spot -> 'Spot interruption'; TaskFailedToStart ->
  Error with the reason; the entrypoint's idle exit (75, read from the
  workspace container's exit code) -> 'stopped after being idle'; a user
  stop is applied silently (P8). is_quota_error, dead, moved to tests.
- The SDK config has a TimeoutConfig (30 s operation / 10 s attempt); the
  watch's per-group poll and StopTask also have tokio bounds.
- Watcher tests cover silent sessions, unsaved work with the WIP push on
  and off, a failing push and the idle exit status; docs updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 12:31:28 -08:00
shadowdaoandClaude Opus 5.5 151b7690df fix(aws): the auth bridge's poll no longer keeps a workspace up
The auth bridge reads /proc/net every 2 s; on the agent that now goes
through ContainerTarget::exec_oneshot_background, which sends
X-Triple-C-Background: 1 so the agent does not count it as activity.
Docker behaviour is unchanged. The idle-stop hint says what idle means
now (R11) and what happens to unsaved work.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 12:31:28 -08:00
shadowdaoandClaude Opus 5.5 95b68ed068 fix(container): idle stop ignores silent sessions and never loses work
- The agent marks requests with X-Triple-C-Background: 1 (and the
  attach/tunnel sessions they open) as not activity (R11).
- triple-c-idle-watch no longer requires zero open execs/tunnels: idle is
  last_activity older than N minutes, no claude, no scheduler job, no
  running clone, and no unsaved git work. With the WIP push on, it pushes
  as claude before signalling and stays up (backing off) when the push
  fails; with it off, dirty repos keep the workspace up.
- An idle stop exits 75 so ECS reports it distinctly from a crash; the
  TERM trap no longer pushes again after the watcher's push.
- start_clone_repos writes done from an EXIT trap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 12:31:19 -08:00
shadowdaoandClaude Opus 5.5 3f986368aa fix(aws): removal deletes the secret at once and words the access point honestly
Removing a project's AWS resources now deletes its secret with
ForceDeleteWithoutRecovery (R10) so the next start can create it again,
and the EFS option is renamed: it removes the access point, while the
files stay on the user's own file system until offboarding (R9).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 12:10:52 -08:00
shadowdaoandClaude Sonnet 5.5 55ec7e33fe docs(aws): fix policy sizes and a constant name
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-15 11:59:31 -08:00
shadowdaoandClaude Sonnet 5.5 595897a5fd docs(aws): phase 5 Fargate workspaces
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-15 11:58:42 -08:00
shadowdaoandClaude Opus 5.5 084fa6efe4 test(aws): guard the live workspace test against hangs and leaks
Review round 1 of Task 9:
- the phase-5 body runs under a 45-minute timeout and each exec under
  180 s, so a hang becomes a panic the guard catches; the body future is
  boxed (moved into the timeout it overflowed the test thread's stack,
  which aborts without any guard);
- scripts/aws-e2e-workspace.sh builds and pushes the image to a throwaway
  ECR repository, runs the test and deletes the repository in an exit
  trap; the test's guard deletes it too (TRIPLEC_E2E_ECR_REPO);
- the guard survives a poisoned lock, closes the tunnel and restores
  AWS_CONFIG_FILE;
- new live probe: a bare elasticfilesystem:TagResource on the user's own
  file system is denied; README records it and the final run (R8 removal
  end state), and the admin command uses xargs -r.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 11:56:40 -08:00
shadowdaoandClaude Opus 5.5 1700cc7985 fix(aws): leave task definitions to admins on removal
Ruling R8. ECS authorizes ecs:DeregisterTaskDefinition against * only,
with no tag condition (verified live), so the workspace tier's
RetireOwnTaskDefinitions could never match, and allowing it on * would
let any user deregister any revision in the account. DeleteTaskDefinitions
is resource-level but deletes only INACTIVE revisions, so it goes too.

Removing an AWS project now stops the task, schedules the secret and
(with discard) deletes the access point, and leaves the task definition
revisions registered, saying so in the log: they hold no secret values,
cost nothing, and RunOwnTasks still needs the owner tag. aws/README.md
tells admins how to deregister them. The policy statement, its checks and
owner-scoped rows, the RuntimeApi methods, the fakes, the removal UI copy
and the live test's final assertion follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 11:34:52 -08:00
shadowdaoandClaude Opus 5.5 e901a08ab6 test(aws): live Fargate workspace lifecycle
aws::live_tests::environment::a_fargate_workspace_round_trips (ignored):
a public environment deployed by the environment admin, a role holding
only the workspace-user files onboarded to it and driving ProjectHost::Aws
through a profile connection: start (Hybrid, 1 vCPU / 2 GB, one public
repo), exec, background clone, ~/.claude persistence across stop/start,
attach without a second RunTask, the stop guard's dry run, the SIGTERM
WIP path, idle stop at 5 minutes, bubblewrap, denials on another owner's
revision and secret, and project removal. TRIPLEC_E2E_IMAGE names the
image; a private ECR image gets a test-only pull policy on the exec role.
A guard stops tasks, retires revisions, deletes access points and the
secret before the fixture destroys the modules.

aws/README.md gains the phase 5 results; the spec's To verify items are
answered. Open: DeregisterTaskDefinition is authorized against * only,
so the workspace tier cannot retire revisions (the test's last assertion
fails until that is decided).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 11:30:33 -08:00
shadowdaoandClaude Opus 5.5 1eed994da7 fix(aws): tag access points at create against their file system
EFS authorizes the elasticfilesystem:TagResource that a tagged
CreateAccessPoint needs against the parent file system's ARN, not the new
access point's: a workspace user's first Hybrid start was denied
("not authorized to perform: elasticfilesystem:TagResource on the
specified resource"). Verified live with a probe role: access-point/*
is denied; file-system/* is allowed, as is * with each of
elasticfilesystem:CreateAction, aws:RequestTag and aws:TagKeys.

TagOwnAccessPointsAtCreate now names file-system/* with the same
conditions (CreateAction = CreateAccessPoint, owner request tag, the
three tag keys); its check and owner-scoped test follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 10:46:59 -08:00
shadowdaoandClaude Opus 5.5 074cb28848 docs(aws): correct the 0.25 vCPU Fargate memory sizes in the phase 5 plan
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 10:31:06 -08:00
shadowdaoandClaude Opus 5.5 08b6d341f2 fix(aws): stop guard review round 2
A failed StopTask removes the stop marker it recorded, so a later stop
pushes as configured. The unchecked guard's Stop anyway sends no choice
and records nothing, so the workspace's own shutdown push still runs as
the dialog says. The idle watcher keeps a pushed/discard marker instead
of overwriting it; the remove-resources dialog sends discard only when
there may be saved files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 10:30:56 -08:00
shadowdaoandClaude Opus 5.5 8441a096c8 fix(aws): stop guard review round 1
The stop guard's choice now reaches the workspace: after a successful
push (or for Stop without pushing) the app records pushed/discard in
/run/triple-c/stop-reason as root, and the entrypoint's shutdown hook
then skips its own push; a marker that can't be written is reported
and the stop goes on. The push runs before the auth bridge is stopped;
a guarded stop of a workspace that already stopped succeeds. The
Fargate table allows only 512/1024/2048 MiB with 256 CPU, pinned on
both sides by a shared fixture. Removal's missing-connection refusal
carries a stable prefix. OpenAI Compatible is allowed on AWS, with a
warning for local addresses and the app's own gateway. HostSection
locks resource actions unless Stopped, the add dialog drops the
environment on a region change, and the repository editor keeps rows
in progress across a refresh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 10:26:53 -08:00
shadowdaoandClaude Opus 5.5 eb7c6c7b21 feat(aws): AWS project settings and the stop guard
Add Project picks Local or an AWS connection, a region and a ready,
joined environment, with repositories instead of folders. The Config
tab's Host section edits CPU/memory (valid pairs only), architecture,
storage, ephemeral size, Spot, idle stop, WIP push and repositories, and
can remove the AWS resources or move the project back to this machine.
Docker access, VPN, port mappings and the gateway backend are disabled on
AWS with the reason; the sandbox shows Off on AWS for now. Stop on an AWS
workspace with unsaved work asks first (Push to WIP branch preselected);
a failed start shows the task's last log lines; removing an AWS project
can delete its saved files, and asks again when its connection is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 10:15:14 -08:00
shadowdaoandClaude Opus 5.5 51042f5d9e feat(aws): stop guard, task log and AWS resource removal commands
check_unsaved_work runs triple-c-wip-push --dry-run through the agent as
claude (checked:false with the reason when the workspace can't be asked);
stop_project_container takes wip: push runs the push first and a failure
aborts the stop with its output. aws_task_log reads the current or last
task's stream in the environment record's log group. remove_aws_resources
removes a stopped project's AWS resources and clears its runtime handles,
so it can move off AWS. add_project takes the host fields; an AWS project
takes repositories, no folders, and no runtime handles from the caller.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 10:15:14 -08:00
shadowdaoandClaude Opus 5.5 b1ac78613c fix(container): aws mode review round 1
Clone repos in the background after the agent starts (progress in
/run/triple-c-clone; an unfinished clone keeps the workspace from idling),
give the task definition stopTimeout 120 for the SIGTERM WIP push, reserve
the TRIPLEC_ env prefix on both hosts, and stop root writing through
claude-controlled links (~/.claude.json written as claude only via the exact
Hybrid link; ~/.ssh merged only through the exact Hybrid link, Docker paths
unchanged). Keep the user's ssh command and add BatchMode, cover dot-folders,
refuse undecodable or over-long file names by name, and upload LFS objects
before the --no-verify push.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 09:59:00 -08:00
shadowdaoandClaude Opus 5.5 51f71212d2 feat(container): aws mode — secret files, repo clone, Hybrid home, WIP push, idle stop
With TRIPLEC_HOST=aws the entrypoint decodes TRIPLEC_FILES into
/tmp/.host-ssh and /tmp/.host-ca and unsets it (and TRIPLEC_REPOS) before
the agent's environment snapshot; links ~/.claude, ~/.claude.json and ~/.ssh
into /mnt/triple-c-home for Hybrid storage; clones TRIPLEC_REPOS as claude
after git credentials and ~/.ssh are set up; runs triple-c-wip-push from the
TERM trap; and starts triple-c-idle-watch, which signals the entrypoint
itself (PID 1 is docker-init under initProcessEnabled). Docker mode is
unchanged: every new step is gated on TRIPLEC_HOST=aws.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 09:46:03 -08:00
shadowdaoandClaude Opus 5.5 8d45a93d63 fix(aws): a start cancels a pending re-attach; keep an unstoppable task recorded
ensure_started cancels a background re-attach instead of waiting for it,
and every register bumps the project's generation, so a late re-attach can
never replace a newer tunnel. A task StopTask refused after a failed start
keeps its ARN. A re-attach that gives up clears the pending flag only if
still current; close_if_task checks and takes under one lock.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 09:30:17 -08:00
shadowdaoandClaude Opus 5.5 37e94b1ee6 fix(aws): record a task as soon as it exists; repair a raced token; guard re-attach
A start stores the task ARN when RunTask returns (or the task is found),
reconcile finds an unrecorded live task, and a failed attach leaves the
project in Error rather than hiding a running task. The winner of a start
race puts its agent token back in the secret. A background re-attach
registers only if the project still runs that task and was not stopped
meanwhile. Removing a project whose connection is gone needs explicit
confirmation. Names come from tofu_modules; files are read with a hard cap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 09:25:53 -08:00
shadowdaoandClaude Opus 5.5 e05f7e3cd8 feat(aws): start, attach and stop a project on its AWS environment
ProjectHost::Aws and the tunnel registry: start looks for the project's
live task before preparing (a running task is attached to with the token
read back from its secret, never rotated), waits for a new access point,
runs, waits, tunnels and checks the agent; a task the start ran is stopped
on any later failure. Stop, remove (resources; data only on request),
reconcile (background re-attach) and the AWS death watch, with exits
confirmed through the registry. Docker-only Reset, migration, staleness
and container info refuse or skip AWS projects; an AWS project with
resources can't be moved off its host. Shutdown closes every tunnel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 09:15:37 -08:00
shadowdaoandClaude Opus 5.5 7fd6fa6aaa feat(aws): environment record, agent token, access point wait and resource removal
RuntimeApi (GetParameter, GetRole, GetSecretValue, DescribeAccessPoints,
task definition retirement, DeleteSecret with a 7-day window,
DeleteAccessPoint) with the decisions in tested functions over it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 09:15:37 -08:00
shadowdaoandClaude Opus 5.5 e43ed26e20 feat(aws): run, find, stop and watch workspace tasks
aws/tasks.rs: TaskApi (+ SdkTaskApi) with RunTask, DescribeTasks (tags),
ListTasks by family, StopTask and a GetLogEvents tail. find_or_run reuses
the project's live task only when its tags name the caller and the
project, and otherwise runs the exact family:revision with the three
ownership tags (FARGATE, or the FARGATE_SPOT capacity provider for Spot),
with a client token so SDK retries cannot start a second task.
wait_ready polls with injectable timing and fails with the stop reason
and the last 50 log lines. Quota refusals become AwsError::QuotaExceeded
and are never retried. classify_stop maps stop codes per the spec.

host/watch.rs: ExitSource::Aws polls an injected project-to-task lookup
every 15 s, per connection+region+cluster, 100 tasks per call; a group
that can't be asked is skipped. has_exited's Agent arm is unchanged (R3).
container_watch::run/spawn take their ExitSource.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 08:56:11 -08:00
shadowdaoandClaude Opus 5.5 30d6b26a42 fix(aws): fingerprint the built task definition; harden workspace lookups
- The fingerprint hashes a canonical rendering of the built request
  (Debug-redacted environment and HashMap log options rendered
  separately, labels excluded) instead of the plan plus a template
  constant, so a builder change can't silently keep old revisions.
- Page ListTaskDefinitions so a longer family can't crowd out the
  caller's revisions.
- Project ids that aren't [A-Za-z0-9-] get a hash suffix in names, so
  ids that sanitise alike can't share a secret.
- Name a secret scheduled for deletion; only mount an available file
  system; drop the unused FileSystemRef.arn.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 08:46:32 -08:00
shadowdaoandClaude Opus 5.5 64ff3baab2 feat(aws): per-project secret, access point and task definition
aws::workspace prepares an AWS project before its task runs: one
Secrets Manager secret holding every project-shaped value (P1; files
as one TRIPLEC_FILES key per R1), the Hybrid EFS access point, and a
task definition whose environment is only TRIPLEC_HOST and COLORTERM
(R2), with every payload key as a valueFrom secret reference.

A revision is reused only when it carries the caller's owner tag, this
project's tag and the expected fingerprint label (other users can
register into any triple-c-* family), always by its exact
family:revision ARN. Payload keys and secrets entries are sorted so
unchanged settings never register a new revision. Names (family,
secret, access point root, log stream prefix, file system token) live
in tofu_modules and use owner_key.

Adds aws-sdk-efs and aws-sdk-cloudwatchlogs (released with the pinned
aws-sdk-ecs; lock gains only their own entries).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 08:39:58 -08:00
shadowdaoandClaude Opus 5.5 7320aaa5d4 fix(aws): document register-into-family residual risk, correct sizes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 08:27:48 -08:00
shadowdaoandClaude Opus 5.5 d1883310dd feat(aws): workspace users register their own task definitions
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 08:26:08 -08:00
shadowdaoandClaude Sonnet 5.5 01e7b2752a refactor(docker): build container env in one host-neutral function
workspace_env() builds every project-shaped KEY=VALUE pair (backends, CA vars,
MANAGED_AUTH_KEYS blanking, custom env, instructions, Claude Code settings);
create_container keeps COLORTERM, HOST_UID/GID and the host lookups (CA
resolution, keychain token) and formats the pairs. Golden vectors recorded from
the pre-refactor block pin the order and values.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-15 08:22:13 -08:00
shadowdaoandClaude Opus 5.5 0fc99738bb feat(aws): project model for the AWS host
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 08:16:56 -08:00
shadowdaoandClaude Opus 5.5 a674f6f196 docs(aws): phase 5 plan — Fargate workspaces
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 07:47:15 -08:00