mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-09-30 08:03:15 +00:00
fix(deploy): use %%...%% for CDK user-data tokens (don't collide with @@ sed) (#21)
The systemd unit booted with a literal `@@OPENSWE_ENV@@` (fetch-config.sh got the token, not "dev" -> exit 2 -> crash-loop) because user-data.sh is double-templated: CDK substitutes @@tokens@@ AND user-data seds @@tokens@@ into the baked systemd/nginx files. CDK's `.replace(/@@OPENSWE_ENV@@/g, "dev")` clobbered the sed PATTERN (`s|@@OPENSWE_ENV@@|...|` -> `s|dev|...|`, a no-op), so the unit's token never got replaced. Same collision hit @@SERVER_NAME@@ (masked by nginx default_server). Fix: CDK tokens move to a DISTINCT delimiter %%...%% (rendered in app-service.ts); the @@...@@ tokens stay for the baked-template seds. No AMI rebuild (templates unchanged). Add a guard test asserting no unresolved %%CDK%% token survives in the synthesized user-data. Also add .github/scripts/** to build-artifacts paths so script-only changes trigger a publish. jest 20/20; tsc + shellcheck clean; rendered user-data: OPENSWE_ENV="dev", SERVER_NAME="openswe-dev.seahaven.com", @@ sed patterns preserved, 16872 B.
This commit is contained in:
parent
9e2b215f08
commit
5fa132205b
4 changed files with 33 additions and 11 deletions
1
.github/workflows/build-artifacts.yml
vendored
1
.github/workflows/build-artifacts.yml
vendored
|
|
@ -40,6 +40,7 @@ on:
|
||||||
- "pyproject.toml"
|
- "pyproject.toml"
|
||||||
- "uv.lock"
|
- "uv.lock"
|
||||||
- ".github/workflows/build-artifacts.yml"
|
- ".github/workflows/build-artifacts.yml"
|
||||||
|
- ".github/scripts/**"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,14 @@ exec > >(tee -a /var/log/open-swe-user-data.log) 2>&1
|
||||||
echo "==> open-swe user-data start $(date -u +%FT%TZ)"
|
echo "==> open-swe user-data start $(date -u +%FT%TZ)"
|
||||||
|
|
||||||
# --- CDK-rendered values -----------------------------------------------------
|
# --- CDK-rendered values -----------------------------------------------------
|
||||||
OPENSWE_ENV="@@OPENSWE_ENV@@" # dev | prod
|
# NOTE: CDK-substituted tokens use %%...%% (rendered by app-service.ts), DISTINCT
|
||||||
ASSETS_BUCKET="@@ASSETS_BUCKET@@" # open-swe-<env>-assets
|
# from the @@...@@ tokens this script seds into the baked systemd/nginx templates.
|
||||||
SERVER_NAME="@@SERVER_NAME@@" # openswe[-dev].seahaven.com
|
# The two MUST NOT share a delimiter: a shared @@OPENSWE_ENV@@ / @@SERVER_NAME@@
|
||||||
ARTIFACT_PREFIX="@@ARTIFACT_PREFIX@@" # e.g. releases/latest
|
# let CDK clobber the sed PATTERN, leaving the unit's token unsubstituted.
|
||||||
|
OPENSWE_ENV="%%OPENSWE_ENV%%" # dev | prod
|
||||||
|
ASSETS_BUCKET="%%ASSETS_BUCKET%%" # open-swe-<env>-assets
|
||||||
|
SERVER_NAME="%%SERVER_NAME%%" # openswe[-dev].seahaven.com
|
||||||
|
ARTIFACT_PREFIX="%%ARTIFACT_PREFIX%%" # e.g. releases/latest
|
||||||
|
|
||||||
# --- fixed layout (must match provision.sh + templates) ----------------------
|
# --- fixed layout (must match provision.sh + templates) ----------------------
|
||||||
SERVICE_USER="openswe"
|
SERVICE_USER="openswe"
|
||||||
|
|
@ -69,13 +73,13 @@ mountpoint -q /run/open-swe || mount /run/open-swe || mount -t tmpfs \
|
||||||
# --- install the deploy script (single source of the app-deploy procedure) ---
|
# --- install the deploy script (single source of the app-deploy procedure) ---
|
||||||
# deploy.sh (deploy/ami/deploy.sh) pulls the release from S3, builds the venv with
|
# deploy.sh (deploy/ami/deploy.sh) pulls the release from S3, builds the venv with
|
||||||
# `uv sync`, and restarts the service. CDK base64-renders the file into the
|
# `uv sync`, and restarts the service. CDK base64-renders the file into the
|
||||||
# @@DEPLOY_SH_B64@@ token below so it is a normal reviewable repo file, not an
|
# %%DEPLOY_SH_B64%% token below so it is a normal reviewable repo file, not an
|
||||||
# inline heredoc. The `open-swe-<env>-deploy` SSM document runs this same script
|
# inline heredoc. The `open-swe-<env>-deploy` SSM document runs this same script
|
||||||
# for every subsequent release.
|
# for every subsequent release.
|
||||||
echo "==> install /opt/open-swe/bin/deploy.sh"
|
echo "==> install /opt/open-swe/bin/deploy.sh"
|
||||||
install -d -o root -g root -m 0755 /opt/open-swe/bin
|
install -d -o root -g root -m 0755 /opt/open-swe/bin
|
||||||
base64 -d >/opt/open-swe/bin/deploy.sh <<'DEPLOY_SH_B64'
|
base64 -d >/opt/open-swe/bin/deploy.sh <<'DEPLOY_SH_B64'
|
||||||
@@DEPLOY_SH_B64@@
|
%%DEPLOY_SH_B64%%
|
||||||
DEPLOY_SH_B64
|
DEPLOY_SH_B64
|
||||||
chmod 0755 /opt/open-swe/bin/deploy.sh
|
chmod 0755 /opt/open-swe/bin/deploy.sh
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -183,11 +183,15 @@ export class AppService extends Construct {
|
||||||
const userData = ec2.UserData.custom(
|
const userData = ec2.UserData.custom(
|
||||||
fs
|
fs
|
||||||
.readFileSync(userDataPath, "utf8")
|
.readFileSync(userDataPath, "utf8")
|
||||||
.replace(/@@OPENSWE_ENV@@/g, env)
|
// %%...%% tokens are CDK-substituted here; they are DELIBERATELY a
|
||||||
.replace(/@@ASSETS_BUCKET@@/g, `${p}-assets`)
|
// different delimiter from the @@...@@ tokens user-data.sh seds into the
|
||||||
.replace(/@@SERVER_NAME@@/g, net.dashboardHost)
|
// baked systemd/nginx templates, so CDK can never clobber a sed pattern
|
||||||
.replace(/@@ARTIFACT_PREFIX@@/g, artifactPrefix)
|
// (a shared @@OPENSWE_ENV@@/@@SERVER_NAME@@ left the unit unsubstituted).
|
||||||
.replace(/@@DEPLOY_SH_B64@@/g, deployShB64),
|
.replace(/%%OPENSWE_ENV%%/g, env)
|
||||||
|
.replace(/%%ASSETS_BUCKET%%/g, `${p}-assets`)
|
||||||
|
.replace(/%%SERVER_NAME%%/g, net.dashboardHost)
|
||||||
|
.replace(/%%ARTIFACT_PREFIX%%/g, artifactPrefix)
|
||||||
|
.replace(/%%DEPLOY_SH_B64%%/g, deployShB64),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.instance = new ec2.Instance(this, "Instance", {
|
this.instance = new ec2.Instance(this, "Instance", {
|
||||||
|
|
|
||||||
|
|
@ -71,4 +71,17 @@ describe("ASCII-only EC2 description fields", () => {
|
||||||
expect(`${id}: ${encoded} bytes`).toBe(encoded < 25600 ? `${id}: ${encoded} bytes` : "OVER 25600");
|
expect(`${id}: ${encoded} bytes`).toBe(encoded < 25600 ? `${id}: ${encoded} bytes` : "OVER 25600");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// CDK substitutes %%...%% tokens in user-data at synth. Any %%TOKEN%% left in the
|
||||||
|
// rendered script means a token wasn't wired in app-service.ts (the @@...@@ tokens
|
||||||
|
// are intentional — user-data seds those into the baked templates at boot).
|
||||||
|
it("user-data has no unresolved %%CDK%% tokens", () => {
|
||||||
|
for (const [id, r] of Object.entries(resources)) {
|
||||||
|
if (r.Type !== "AWS::EC2::Instance") continue;
|
||||||
|
const ud = (r.Properties?.UserData as { "Fn::Base64"?: string }) ?? {};
|
||||||
|
const script = typeof ud["Fn::Base64"] === "string" ? ud["Fn::Base64"] : "";
|
||||||
|
const leftover = script.match(/%%[A-Z0-9_]+%%/g) ?? [];
|
||||||
|
expect(`${id}: ${leftover.join(",")}`).toBe(`${id}: `);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue