cursedops 0.18.0 → 0.19.0
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/package.json +1 -1
- package/src/smoke.ts +31 -5
- package/src/workerDeploy.ts +3 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cursedops",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "The build-and-ops answers this generation's apps wrote independently and identically: finding a generation's roots — and printing a command that runs when pasted — without knowing a path, the generation's whole-tree laws run over one repo from a checkout or a worktree, macOS launchd agent install/replace/remove and the live port a job serves, the scaffolding and verdicts of a deployed smoke (origin probe, the smoke's own environment, a network that lies about DNS, a settled version), the static-serving helpers eight apps copied — the path-traversal guard among them — the API floor that keeps an unmatched /api/... from ever being answered with the app shell, the commit and dirty flag a checkout-served process reports, the Cloudflare Worker deploy toolkit four apps copied (the deploy sequence, exact-set secrets over a pipe, origin-first rollback, the curl edge fetch, the row-for-row D1 import proof, the billed-CPU tail check around a deploy's walk and smoke, and each app's worker:secrets and worker:smoke main as one function of its data), the relay a Worker fronts a Mac-bound app with (the Durable Object, the frames, the Mac's dialer and key rotation — lifted from station for roms — and the signed-in stage walk's skeleton and the relay app's whole worker:deploy), the Worker import-graph and await-port checks every Worker app's suite runs over its own source, and the public-surface ratchet three published libraries each carried a forked copy of. Mechanism only — no app knows its name from here. Bun, zero runtime dependencies (typescript is an optional peer, for public-surface only), ships source.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
package/src/smoke.ts
CHANGED
|
@@ -1030,8 +1030,13 @@ export interface WorkerSmokeSpec {
|
|
|
1030
1030
|
deployment: { env: string; workerName: string; publicUrl: string; previewUrl: string | null };
|
|
1031
1031
|
/** Addresses given on the command line. Empty: the preview (no cache in front) and the public URL. */
|
|
1032
1032
|
urls?: readonly string[];
|
|
1033
|
-
/**
|
|
1033
|
+
/**
|
|
1034
|
+
* The checkout's HEAD, as `/healthz` reports a commit (`git rev-parse --short=8 HEAD`). Under
|
|
1035
|
+
* `runWorkerDeploy` the commit it STAMPED wins — see {@link DEPLOYED_COMMIT_ENV}.
|
|
1036
|
+
*/
|
|
1034
1037
|
head: string;
|
|
1038
|
+
/** Where {@link DEPLOYED_COMMIT_ENV} is read. Default `process.env`. */
|
|
1039
|
+
env?: Record<string, string | undefined>;
|
|
1035
1040
|
/**
|
|
1036
1041
|
* Every private route; each must refuse an anonymous caller with 401 (`door: "access"`: 403 on
|
|
1037
1042
|
* the preview, 200 through the token on the public host). Empty is a FAILURE.
|
|
@@ -1059,6 +1064,25 @@ export interface WorkerSmokeSpec {
|
|
|
1059
1064
|
log?: (line: string) => void;
|
|
1060
1065
|
}
|
|
1061
1066
|
|
|
1067
|
+
/**
|
|
1068
|
+
* 🔴 The commit `runWorkerDeploy` stamped into the Worker it just uploaded, handed to its smoke.
|
|
1069
|
+
*
|
|
1070
|
+
* Each app's smoke reads its checkout's HEAD when it starts, minutes after the deploy read it to
|
|
1071
|
+
* stamp the build. On 2026-10-18 music's fast lane built and stamped `a0bca487`, a batch landed an
|
|
1072
|
+
* e2e-only commit two minutes in, and the smoke — asking for the new HEAD `43c2bae8` — waited out
|
|
1073
|
+
* its steady window and then failed a healthy production deploy on `commit`. The smoke proves
|
|
1074
|
+
* what was DEPLOYED, so it asks for this commit when it is set, and for HEAD only when run alone.
|
|
1075
|
+
*/
|
|
1076
|
+
export const DEPLOYED_COMMIT_ENV = "CURSEDOPS_DEPLOYED_COMMIT";
|
|
1077
|
+
|
|
1078
|
+
/** The commit `/healthz` must report, and the words the `commit` check says it in. */
|
|
1079
|
+
export function expectedCommit(spec: Pick<WorkerSmokeSpec, "head" | "env">): { commit: string; said: string } {
|
|
1080
|
+
const stamped = (spec.env ?? process.env)[DEPLOYED_COMMIT_ENV]?.trim();
|
|
1081
|
+
if (!stamped) return { commit: spec.head, said: `HEAD ${spec.head}` };
|
|
1082
|
+
const commit = stamped.slice(0, spec.head.length || 8);
|
|
1083
|
+
return { commit, said: commit === spec.head ? `HEAD ${commit}` : `deployed ${commit} (HEAD has moved on to ${spec.head} since)` };
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1062
1086
|
/**
|
|
1063
1087
|
* The whole anonymous `worker:smoke` of a deployed Worker, lifted out of `apps/family` and
|
|
1064
1088
|
* `apps/music` (task 2145). Per address: `/healthz` settles on THIS commit with the door mounted
|
|
@@ -1078,6 +1102,7 @@ export async function runWorkerSmoke(spec: WorkerSmokeSpec): Promise<number> {
|
|
|
1078
1102
|
? [...spec.urls]
|
|
1079
1103
|
: [...new Set([deployment.previewUrl, deployment.publicUrl].filter((u): u is string => Boolean(u)))];
|
|
1080
1104
|
const smoke = createSmoke({ base: deployment.publicUrl || (urls[0] as string), ...spec.smokeOptions });
|
|
1105
|
+
const want = expectedCommit(spec);
|
|
1081
1106
|
|
|
1082
1107
|
for (const base of urls) {
|
|
1083
1108
|
const host = new URL(base).hostname;
|
|
@@ -1104,7 +1129,7 @@ export async function runWorkerSmoke(spec: WorkerSmokeSpec): Promise<number> {
|
|
|
1104
1129
|
try {
|
|
1105
1130
|
const read = await steadyHealth<Record<string, unknown>>(
|
|
1106
1131
|
() => ask("/healthz", healthRead),
|
|
1107
|
-
(body) => body.commit ===
|
|
1132
|
+
(body) => body.commit === want.commit && body.apiServed === true,
|
|
1108
1133
|
spec.steady,
|
|
1109
1134
|
);
|
|
1110
1135
|
health = read.body;
|
|
@@ -1120,7 +1145,7 @@ export async function runWorkerSmoke(spec: WorkerSmokeSpec): Promise<number> {
|
|
|
1120
1145
|
health.apiServed === true,
|
|
1121
1146
|
`apiServed ${JSON.stringify(health.apiServed)}${health.apiRefusal ? ` (${health.apiRefusal})` : ""}`,
|
|
1122
1147
|
);
|
|
1123
|
-
smoke.record(`${tag} commit`, health.commit ===
|
|
1148
|
+
smoke.record(`${tag} commit`, health.commit === want.commit, `serving ${JSON.stringify(health.commit)}, ${want.said}`);
|
|
1124
1149
|
smoke.record(
|
|
1125
1150
|
`${tag} publicUrl`,
|
|
1126
1151
|
health.publicUrl === deployment.publicUrl,
|
|
@@ -1180,6 +1205,7 @@ async function accessDoorSmoke(
|
|
|
1180
1205
|
log: (line: string) => void,
|
|
1181
1206
|
): Promise<number> {
|
|
1182
1207
|
const { deployment } = spec;
|
|
1208
|
+
const want = expectedCommit(spec);
|
|
1183
1209
|
const anonymous = spec.anonymousFetch;
|
|
1184
1210
|
if (!anonymous) {
|
|
1185
1211
|
smoke.refuseEnvironment("the anonymous fetch", 'door: "access" needs `anonymousFetch` — a fetch that carries NO Access token');
|
|
@@ -1199,7 +1225,7 @@ async function accessDoorSmoke(
|
|
|
1199
1225
|
let health: Record<string, unknown>;
|
|
1200
1226
|
let status: number;
|
|
1201
1227
|
try {
|
|
1202
|
-
const read = await steadyHealth<Record<string, unknown>>(() => ask("/healthz", healthRead), (body) => body.commit ===
|
|
1228
|
+
const read = await steadyHealth<Record<string, unknown>>(() => ask("/healthz", healthRead), (body) => body.commit === want.commit, spec.steady);
|
|
1203
1229
|
health = read.body;
|
|
1204
1230
|
status = read.response.status;
|
|
1205
1231
|
} catch (error) {
|
|
@@ -1208,7 +1234,7 @@ async function accessDoorSmoke(
|
|
|
1208
1234
|
continue;
|
|
1209
1235
|
}
|
|
1210
1236
|
smoke.record(`${tag} healthz`, status === 200 && health.runtime === "worker", `${status}, runtime ${JSON.stringify(health.runtime)}`);
|
|
1211
|
-
smoke.record(`${tag} commit`, health.commit ===
|
|
1237
|
+
smoke.record(`${tag} commit`, health.commit === want.commit, `serving ${JSON.stringify(health.commit)}, ${want.said}`);
|
|
1212
1238
|
smoke.record(
|
|
1213
1239
|
`${tag} access`,
|
|
1214
1240
|
health.access === true,
|
package/src/workerDeploy.ts
CHANGED
|
@@ -60,6 +60,7 @@ import { join } from "node:path";
|
|
|
60
60
|
import { liveColumns, liveColumnsQueries, missingColumnStatements, schemaTables } from "cursedops/d1-columns";
|
|
61
61
|
import { wranglerRows } from "cursedops/d1-import";
|
|
62
62
|
import { forgeCodeRoot, forgeState } from "cursedops/roots";
|
|
63
|
+
import { DEPLOYED_COMMIT_ENV } from "cursedops/smoke";
|
|
63
64
|
import { appendLedger, deferral, readShipSetting, type ShipEventLine, type ShipNowWhere, type ShipSetting } from "cursedops/ship";
|
|
64
65
|
import { type StageLeaseResult, takeStageLease } from "cursedops/stage-lease";
|
|
65
66
|
|
|
@@ -977,7 +978,8 @@ export function runWorkerDeploy(spec: WorkerDeploySpec, deps: DeployDeps): Deplo
|
|
|
977
978
|
step(`smoke every address this deployment answers on${spec.cpuTail ? ", under a CPU tail" : ""}`);
|
|
978
979
|
enter("smoke");
|
|
979
980
|
const smoke = spec.cpuTail ? underCpuTail(spec.cpuTail, spec.env, spec.smoke) : spec.smoke;
|
|
980
|
-
|
|
981
|
+
// The commit stamped above, not the HEAD the smoke would read minutes later (`DEPLOYED_COMMIT_ENV`).
|
|
982
|
+
const smoked = deps.run(smoke, { [DEPLOYED_COMMIT_ENV]: commit });
|
|
981
983
|
if (spec.cpuTail && smoked === TAIL_UNATTACHED_EXIT) unmeasured.push("the smoke");
|
|
982
984
|
else if (smoked !== 0) {
|
|
983
985
|
return stop(
|