@m-kopa/launchpad-cli 0.43.0 → 0.45.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/CHANGELOG.md +49 -0
- package/dist/cli.js +14 -2
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/deploy/deployment-status.d.ts +5 -0
- package/dist/deploy/deployment-status.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +2 -2
- package/skills/launchpad-content-pr/SKILL.md +1 -1
- package/skills/launchpad-deploy/SKILL.md +1 -1
- package/skills/launchpad-deploy-status/SKILL.md +1 -1
- package/skills/launchpad-destroy/SKILL.md +1 -1
- package/skills/launchpad-identity/SKILL.md +65 -27
- package/skills/launchpad-onboard/SKILL.md +1 -1
- package/skills/launchpad-report/SKILL.md +1 -1
- package/skills/launchpad-status/SKILL.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,55 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
6
6
|
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html);
|
|
7
7
|
pre-1.0 minor bumps may carry breaking changes per ADR 0005.
|
|
8
8
|
|
|
9
|
+
## 0.45.0 — 2026-07-05
|
|
10
|
+
|
|
11
|
+
**Self-serve recovery of a build-failed app (PS-1934).** An app stuck in a
|
|
12
|
+
`failed` lifecycle because of a build bug now recovers through the normal
|
|
13
|
+
`launchpad deploy` flow — no break-glass, no separate `launchpad recover`:
|
|
14
|
+
|
|
15
|
+
- **Auto-reconcile `failed → live`.** Once your fixing deploy's Cloudflare
|
|
16
|
+
Pages build is **verified serving**, the platform flips the record back to
|
|
17
|
+
`live` on the next `launchpad status` / `launchpad watch` read (which
|
|
18
|
+
`deploy` runs for you). `status` surfaces a `✓ recovered:` line so the
|
|
19
|
+
repair is visible, not silent. Scoped to **build** failures only — a
|
|
20
|
+
security-verdict `failed` (origin reachable without auth) is never
|
|
21
|
+
auto-cleared by a green build.
|
|
22
|
+
- **Honest failed-app deploy UX.** An empty-delta deploy to a `failed` app now
|
|
23
|
+
says so plainly (`slug_failed`) and points at the fix path, instead of an
|
|
24
|
+
opaque 409.
|
|
25
|
+
- **`recover` stays** as the explicit reconcile-only path; the docs now
|
|
26
|
+
cross-reference the broken-CI case (PS-1932), where `launchpad deploy` (bot
|
|
27
|
+
bypass) is the supported recovery.
|
|
28
|
+
|
|
29
|
+
Platform-side (ships with the bot): the `redeploy` path now re-ensures the
|
|
30
|
+
D1 binding like `deploy` does, so a redeploy-based recovery can't leave the
|
|
31
|
+
database unbound (the stock-dispatch-tracker 500 root cause).
|
|
32
|
+
|
|
33
|
+
## 0.44.0 — 2026-07-05
|
|
34
|
+
|
|
35
|
+
**Identity guide crystal-clarity — fixes the "gateway signs me in but the app
|
|
36
|
+
says not signed in" class.** The `/launchpad-identity` skill told authors to read
|
|
37
|
+
`GATEWAY_ISSUER / GATEWAY_AUD / GATEWAY_JWKS_URL` and (wrongly) that those are
|
|
38
|
+
"what is live on Cloudflare" — but the platform engine actually provisions the
|
|
39
|
+
gateway verifier values under the legacy names `CF_ACCESS_TEAM_DOMAIN /
|
|
40
|
+
CF_ACCESS_AUD / JWKS_URL` for a `react+api` app. An app that followed the guide
|
|
41
|
+
read only `GATEWAY_*`, found them undefined, and silently fail-closed every user
|
|
42
|
+
to anonymous.
|
|
43
|
+
|
|
44
|
+
- **Skill verifier snippet now reads BOTH name sets via `||`** (`GATEWAY_ISSUER
|
|
45
|
+
|| CF_ACCESS_TEAM_DOMAIN`, etc.) — copy it and you are immune to the mismatch
|
|
46
|
+
whichever set your project carries.
|
|
47
|
+
- **Corrected the false "GATEWAY_* are live on Cloudflare" claim**; added an
|
|
48
|
+
explicit two-convention name table, a gateway-vs-Cloudflare-Access note (the
|
|
49
|
+
issuer is `auth.launchpad.m-kopa.us`, **not** `*.cloudflareaccess.com`), the
|
|
50
|
+
bare-host `aud` rule, and the `secret_text` + same-deploy/redeploy requirement.
|
|
51
|
+
- **`docs/guide/auth.md`**: banner correcting the gateway `/api/me` shape — it
|
|
52
|
+
carries `sub`/`email`/`name` only (**no `groups`** — never authorise from it),
|
|
53
|
+
and fail-closed is `200 {authenticated:false}`, not `401`.
|
|
54
|
+
- **`@m-kopa/platform-auth` `types.ts`**: fixed the docstring that claimed
|
|
55
|
+
`preferredUsername` comes from a `preferred_username` claim — the runtime reads
|
|
56
|
+
the `email` claim (the IdP maps the Entra UPN into it).
|
|
57
|
+
|
|
9
58
|
## 0.43.0 — 2026-07-05
|
|
10
59
|
|
|
11
60
|
**`launchpad deploy` now shows a pre-deploy config diff (PS-1920).** Before a
|
package/dist/cli.js
CHANGED
|
@@ -19,7 +19,7 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
19
19
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
20
20
|
|
|
21
21
|
// src/version.ts
|
|
22
|
-
var CLI_VERSION = "0.
|
|
22
|
+
var CLI_VERSION = "0.45.0";
|
|
23
23
|
|
|
24
24
|
// src/config.ts
|
|
25
25
|
import * as os from "node:os";
|
|
@@ -3763,7 +3763,8 @@ async function fetchDeploymentStatus(cfg, slug, fetcher = fetch) {
|
|
|
3763
3763
|
slug: typeof raw.slug === "string" ? raw.slug : slug,
|
|
3764
3764
|
supported: raw.supported,
|
|
3765
3765
|
liveDeployment: raw.liveDeployment ?? null,
|
|
3766
|
-
lastSuccessfulDeployment: raw.lastSuccessfulDeployment ?? null
|
|
3766
|
+
lastSuccessfulDeployment: raw.lastSuccessfulDeployment ?? null,
|
|
3767
|
+
...raw.reconciledToLive === true ? { reconciledToLive: true } : {}
|
|
3767
3768
|
};
|
|
3768
3769
|
}
|
|
3769
3770
|
|
|
@@ -5139,6 +5140,9 @@ function surfaceDeployment(out, io) {
|
|
|
5139
5140
|
const dep = out.deployment;
|
|
5140
5141
|
if (dep === undefined || dep === null || !dep.supported)
|
|
5141
5142
|
return;
|
|
5143
|
+
if (dep.reconciledToLive === true) {
|
|
5144
|
+
io.out(" ✓ recovered: this app was in a failed state; its verified-live build reconciled the record failed→live (no `launchpad recover` needed).");
|
|
5145
|
+
}
|
|
5142
5146
|
const live = dep.liveDeployment;
|
|
5143
5147
|
if (live === null) {
|
|
5144
5148
|
io.out(" last deployment: none — Cloudflare Pages has no production deployment yet.");
|
|
@@ -7319,6 +7323,14 @@ async function runModelADeploy(args) {
|
|
|
7319
7323
|
}
|
|
7320
7324
|
return 1;
|
|
7321
7325
|
}
|
|
7326
|
+
if (result.status === 409 && errorCode === "slug_failed") {
|
|
7327
|
+
io.err(`launchpad deploy: app "${slug}" is in a FAILED state, and this deploy adds no new content (nothing to re-drive the build).`);
|
|
7328
|
+
if (typeof body.message === "string") {
|
|
7329
|
+
io.err(` ${body.message}`);
|
|
7330
|
+
}
|
|
7331
|
+
io.err(` Deploy a content change to re-drive the build (it reconciles failed→live automatically once verified serving — watch \`launchpad status ${slug}\`), or \`launchpad deploy --resume ${slug}\`.`);
|
|
7332
|
+
return 1;
|
|
7333
|
+
}
|
|
7322
7334
|
if (result.status === 409 && isStaleBlock(body)) {
|
|
7323
7335
|
surfaceStaleBlock(body, io);
|
|
7324
7336
|
return 1;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
|
|
@@ -26,6 +26,11 @@ export interface DeploymentStatusView {
|
|
|
26
26
|
readonly createdOn: string;
|
|
27
27
|
readonly url: string | null;
|
|
28
28
|
} | null;
|
|
29
|
+
/** PS-1934 AC1 — true when THIS read auto-reconciled a build-failed app
|
|
30
|
+
* back to `live` (its latest build is verified serving). Lets `status` /
|
|
31
|
+
* `watch` / the post-deploy verify surface "record reconciled failed→live"
|
|
32
|
+
* rather than the repair happening silently. */
|
|
33
|
+
readonly reconciledToLive?: boolean;
|
|
29
34
|
}
|
|
30
35
|
/** One standing-exception inventory entry (sp-devlp1 T3 / D2) — a
|
|
31
36
|
* policy/boundary/build-command violation observed in content already
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deployment-status.d.ts","sourceRoot":"","sources":["../../src/deploy/deployment-status.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,KAAK,GAAG,SAAS,CAAC;AAC/D,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAC;AAEhE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACtE,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,cAAc,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACnD,yEAAyE;IACzE,QAAQ,CAAC,wBAAwB,EAAE;QACjC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7B,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"deployment-status.d.ts","sourceRoot":"","sources":["../../src/deploy/deployment-status.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,KAAK,GAAG,SAAS,CAAC;AAC/D,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAC;AAEhE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACtE,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,cAAc,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACnD,yEAAyE;IACzE,QAAQ,CAAC,wBAAwB,EAAE;QACjC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7B,GAAG,IAAI,CAAC;IACT;;;qDAGiD;IACjD,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED;;;wEAGwE;AACxE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,OAAO,KAAa,GAC5B,OAAO,CAAC,SAAS,qBAAqB,EAAE,GAAG,IAAI,CAAC,CAsBlD;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,OAAO,KAAa,GAC5B,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAwBtC"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "0.
|
|
1
|
+
export declare const CLI_VERSION = "0.45.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@m-kopa/launchpad-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Launchpad CLI
|
|
3
|
+
"version": "0.45.0",
|
|
4
|
+
"description": "Launchpad CLI \u2014 clone / deploy / review / merge against Launchpad-managed apps. Talks to the portal-bot endpoints (SCOPE-M-760 / T4).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"launchpad": "./dist/cli.js"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-content-pr
|
|
3
3
|
description: Push a content change to a Launchpad app via `launchpad deploy` and verify it shipped via `launchpad status`. Covers the post-first-deploy iteration loop (edit → deploy → verify) — subsequent deploys commit directly to the app repo's main and the Pages build runs asynchronously, so verification is its own step. Use when someone says "push a content change", "ship an update", "/launchpad-content-pr", "verify my deploy", or after `/launchpad-deploy` reports `done` and they want to follow up with an edit.
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.45.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-deploy
|
|
3
3
|
description: Walk a Launchpad user through deploying an app from their local working directory (Model A — `launchpad init` + `launchpad deploy`). Wraps the CLI verbs end-to-end: detects the app shape, scaffolds `launchpad.yaml`, resolves the allowed Entra group via `launchpad groups`, bundles the CWD via `launchpad deploy`, and watches the rollout via `launchpad status`. Use when someone says "deploy a new app", "ship my app to Launchpad", "/launchpad-deploy", "I have an app locally — get it on Launchpad", or any variant. Resume/abandon for legacy in-flight provisioning is at the bottom.
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.45.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-deploy-status
|
|
3
3
|
description: Show the current provisioning stage + failure reason for a Launchpad app via `launchpad status` (Model A drift + deployment_verified) and `launchpad apps` (lifecycle bucket), or watch provisioning live with `launchpad watch`. Renders the M-892 stage trace for in-flight provisioning, and is the canonical home for `launchpad recover` (repair a terminal-failed app record that is actually live). Use when someone says "what's the status of demo-X", "/launchpad-deploy-status", "is my deploy stuck", "watch my deploy go live", "watch provisioning", "my app says failed but it's serving", or after `/launchpad-deploy` reports a non-`done` terminal stage.
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.45.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-destroy
|
|
3
3
|
description: Tear down a Launchpad app end-to-end via `launchpad destroy` — Cloudflare Pages project, edge-auth wiring (gateway KV/audience entries, or the Access app for `auth: access` apps), custom hostname, platform-repo TF, and the app repo (archive-renamed). Owner-only verb with a two-step destructive confirmation. Use when someone says "destroy this app", "/launchpad-destroy", "tear down `<slug>`", "delete the app", or asks to clean up a smoke-test / orphan / retired app.
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.45.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-identity
|
|
3
3
|
description: Teach an app author how to use the signed-in user's identity inside a Launchpad app — read the gateway-forwarded X-Launchpad-User-Assertion in a Pages Function, VERIFY it with @m-kopa/platform-auth (fail-closed), and show who's logged in (sub/email/name). Use when someone says "who is logged in", "show the current user", "get the user's email in my app", "auth in my launchpad app", "read the user identity", "/launchpad-identity", or is wiring up an /api/me for a gateway-fronted app.
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.45.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -130,10 +130,17 @@ export async function onRequestGet(context) {
|
|
|
130
130
|
const token = request.headers.get(IDENTITY_HEADER);
|
|
131
131
|
if (!token) return anonymous(); // no token → anonymous / public path
|
|
132
132
|
|
|
133
|
-
|
|
134
|
-
|
|
133
|
+
// Read BOTH the canonical GATEWAY_* names AND the legacy CF_ACCESS_* / JWKS_URL
|
|
134
|
+
// names the platform engine currently provisions for react+api apps (identical
|
|
135
|
+
// gateway values, older key names). Tolerating both via `||` is what keeps this
|
|
136
|
+
// verifier working no matter which set your app was scaffolded with — skipping
|
|
137
|
+
// the fallback is the #1 cause of "gateway signs me in but the app says not
|
|
138
|
+
// signed in". See "Required env vars" below.
|
|
139
|
+
const issuer = env.GATEWAY_ISSUER || env.CF_ACCESS_TEAM_DOMAIN; // gateway iss
|
|
140
|
+
const audience = env.GATEWAY_AUD || env.CF_ACCESS_AUD; // this app's aud (your host)
|
|
135
141
|
const jwksUrl =
|
|
136
142
|
env.GATEWAY_JWKS_URL ||
|
|
143
|
+
env.JWKS_URL ||
|
|
137
144
|
(issuer ? `${issuer.replace(/\/$/, '')}/.well-known/jwks.json` : null);
|
|
138
145
|
|
|
139
146
|
// Misconfigured verify env → fail CLOSED. Never trust an unverifiable token.
|
|
@@ -227,30 +234,56 @@ vars — is identical to the example above.
|
|
|
227
234
|
|
|
228
235
|
## Required env vars — `secret_text`, MANDATORY
|
|
229
236
|
|
|
230
|
-
Verification needs three
|
|
231
|
-
|
|
237
|
+
Verification needs three values on your app: the gateway **issuer**, **your
|
|
238
|
+
app's audience**, and the **JWKS URL**. Two things trip people up — a value
|
|
239
|
+
gotcha and a name gotcha. Read both.
|
|
232
240
|
|
|
233
|
-
|
|
241
|
+
**The value contract (identical whichever key names you use):**
|
|
242
|
+
|
|
243
|
+
| Value | Set it to | Notes |
|
|
244
|
+
|---|---|---|
|
|
245
|
+
| issuer (`iss`) | `https://auth.launchpad.m-kopa.us` | the gateway token issuer — the **same for every app** |
|
|
246
|
+
| audience (`aud`) | `<your-slug>.launchpad.m-kopa.us` | **your app's bare public host** — no `https://`, no port, no trailing slash. Exact-match replay guard: a wrong value fails closed. |
|
|
247
|
+
| jwks | `https://auth.launchpad.m-kopa.us/.well-known/jwks.json` | optional — derived from the issuer if unset |
|
|
248
|
+
|
|
249
|
+
**The name gotcha — read BOTH name sets.** There are currently **two** key-name
|
|
250
|
+
conventions for these same three values, and which one your app has depends on
|
|
251
|
+
how it was created:
|
|
252
|
+
|
|
253
|
+
| Convention | Keys | Where it comes from |
|
|
234
254
|
|---|---|---|
|
|
235
|
-
| `GATEWAY_ISSUER`
|
|
236
|
-
| `
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
>
|
|
240
|
-
>
|
|
241
|
-
>
|
|
242
|
-
>
|
|
243
|
-
>
|
|
244
|
-
>
|
|
245
|
-
>
|
|
246
|
-
>
|
|
247
|
-
>
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
255
|
+
| **Canonical** (this guide) | `GATEWAY_ISSUER` / `GATEWAY_AUD` / `GATEWAY_JWKS_URL` | the name set we are standardising on |
|
|
256
|
+
| **Legacy** (auto-provisioned) | `CF_ACCESS_TEAM_DOMAIN` / `CF_ACCESS_AUD` / `JWKS_URL` | **what the platform engine actually sets on a `react+api` app today** — correct gateway values, older names (`per-app-workspace.ts`) |
|
|
257
|
+
|
|
258
|
+
> ⚠️ **Do NOT assume `GATEWAY_*` are "already live."** A `react+api` app
|
|
259
|
+
> scaffolded by the platform is born with the **`CF_ACCESS_*` / `JWKS_URL`**
|
|
260
|
+
> keys — the engine reuses the pre-gateway Cloudflare-Access names for the
|
|
261
|
+
> gateway values. If your verifier reads **only** `GATEWAY_*`, those keys are
|
|
262
|
+
> `undefined`, the `if (!jwksUrl || !issuer || !audience) return anonymous()`
|
|
263
|
+
> guard fires, and **every** user silently goes anonymous: the gateway signs
|
|
264
|
+
> you in, but your app renders its own "not signed in" screen. **This is the #1
|
|
265
|
+
> cause of that symptom.** The verifier snippet above already reads both name
|
|
266
|
+
> sets via `||` — keep the fallback and you are immune to the mismatch,
|
|
267
|
+
> whichever set your project carries.
|
|
268
|
+
|
|
269
|
+
> **This is the gateway, not Cloudflare Access.** Despite the name,
|
|
270
|
+
> `CF_ACCESS_TEAM_DOMAIN` here holds the **gateway** issuer
|
|
271
|
+
> `https://auth.launchpad.m-kopa.us` — **not** a `*.cloudflareaccess.com`
|
|
272
|
+
> domain. Any doc that tells you to point the issuer at `cloudflareaccess.com`
|
|
273
|
+
> is describing the legacy Cloudflare-Access channel, not the
|
|
274
|
+
> `X-Launchpad-User-Assertion` gateway channel these apps use. (Also: it is
|
|
275
|
+
> `GATEWAY_AUD`, **not** `GATEWAY_AUDIENCE`; and ignore the illustrative
|
|
276
|
+
> `AUTH_ISS` / `APP_AUD` names in older contract-doc snippets.)
|
|
277
|
+
|
|
278
|
+
**Set them as `secret_text`, in the SAME deploy as the code that reads them.**
|
|
279
|
+
|
|
280
|
+
> ⚠️ **`secret_text` + same-deploy, or identity goes dark.** Plain-text env is
|
|
281
|
+
> silently dropped by Cloudflare Pages under partial-PATCH, and env only binds
|
|
282
|
+
> on a **new** deployment. So if you set the vars as plain-text, **or** push
|
|
283
|
+
> them *after* your last deploy, they are not live on the running deployment —
|
|
284
|
+
> `issuer`/`audience` are `undefined`, the fail-closed guard fires, and identity
|
|
285
|
+
> is dark until you re-add them `secret_text` and **redeploy**. Set them
|
|
286
|
+
> `secret_text` and ship them in the same `launchpad deploy` as the consumer.
|
|
254
287
|
|
|
255
288
|
## Anti-pattern — do NOT do this
|
|
256
289
|
|
|
@@ -276,8 +309,13 @@ An unverified payload can be forged by anyone who can reach your origin
|
|
|
276
309
|
- [ ] **Fails closed** to anonymous on missing token, missing env, or any
|
|
277
310
|
verify error — never returns the unverified user.
|
|
278
311
|
- [ ] No unsigned `decodeJwtPayload` on the auth path.
|
|
279
|
-
- [ ]
|
|
280
|
-
|
|
312
|
+
- [ ] Verifier reads **both** name sets via `||` (`GATEWAY_ISSUER ||
|
|
313
|
+
CF_ACCESS_TEAM_DOMAIN`, etc.) so it works whichever set your app carries.
|
|
314
|
+
- [ ] Confirmed which env var **names** are actually live on your deployed
|
|
315
|
+
project (`CF_ACCESS_*` on an engine-scaffolded react+api app, `GATEWAY_*`
|
|
316
|
+
if you hand-set them), set as **`secret_text`**, shipped in the **same**
|
|
317
|
+
deploy — then `launchpad deploy` again if you added them after the last one.
|
|
318
|
+
- [ ] `aud` is your **bare host** (`<slug>.launchpad.m-kopa.us`), no scheme/port.
|
|
281
319
|
- [ ] No authorization decision is made from `/api/me` — attribution only.
|
|
282
320
|
|
|
283
321
|
## Don'ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-onboard
|
|
3
3
|
description: One-time setup for the Launchpad CLI + Claude Code skill bundle. Verifies the `launchpad` CLI is installed and current, runs `launchpad whoami` to confirm the session is fresh, and checks the bundled skills are installed and in lock-step with the CLI. Idempotent — safe to re-run any time. Use when someone says "set me up for Launchpad", "I just got a new machine and want to use Launchpad", "/launchpad-onboard", or any of the other launchpad-* skills fails on a prereq check.
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.45.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-report
|
|
3
3
|
description: File a bug report or feature request to the Launchpad team's tracker from the CLI. Use when someone reports something broken, hits an error in a launchpad command, or wishes a feature existed — e.g. "this is broken", "report a bug", "can you file that", "I wish launchpad could…", "/launchpad-bug", "/launchpad-feature". Always confirm and show exactly what you'll send before filing; never file silently.
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.45.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-status
|
|
3
3
|
description: Show whether a Launchpad app's local launchpad.yaml matches what's deployed, and read the deployed manifest. Wraps `launchpad pull` (fetch deployed YAML) and `launchpad status` (drift report). Use when someone says "is my app in sync", "what's deployed", "show drift", "/launchpad-status", "/launchpad-pull", or after `launchpad deploy` to verify the change landed.
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.45.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|