@rtrentjones/greenlight 0.2.11 → 0.2.13
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/assets/skills/provider-vercel/SKILL.md +1 -1
- package/dist/bin.js +32 -20
- package/package.json +4 -4
|
@@ -45,7 +45,7 @@ without carrying the wrapper's `greenlight.config.ts` into the tool repo.
|
|
|
45
45
|
**Deployment Protection gotcha:** `deployment_status.target_url` is the `*.vercel.app` *deployment*
|
|
46
46
|
URL, which Vercel **Deployment Protection** gates (→ **401**) even though the public custom domain
|
|
47
47
|
is 200. To verify the real app, create a **Protection Bypass for Automation** secret (Vercel →
|
|
48
|
-
project → Settings → Deployment Protection) and set it as `
|
|
48
|
+
project → Settings → Deployment Protection) and set it as `VERCEL_AUTOMATION_BYPASS_SECRET_<TOOL>` (per-tool — the bypass value is per Vercel project, so a second vercel tool never collides) on the
|
|
49
49
|
tool repo — the api check sends it as `x-vercel-protection-bypass` and asserts 200. Without it the
|
|
50
50
|
generated spec asserts **401** (the deployment is served + protected), so the gate stays green.
|
|
51
51
|
|
package/dist/bin.js
CHANGED
|
@@ -276,12 +276,11 @@ var PACKS = [
|
|
|
276
276
|
});
|
|
277
277
|
return { ok: okStatus(r), detail: `HTTP ${r.status}` };
|
|
278
278
|
}
|
|
279
|
-
},
|
|
280
|
-
{
|
|
281
|
-
envVar: "TF_VAR_supabase_database_password",
|
|
282
|
-
label: "database password (ignored when importing an existing project)",
|
|
283
|
-
optional: true
|
|
284
279
|
}
|
|
280
|
+
// NOTE: the database password is PER-PROJECT, so it's emitted as a per-tool variable
|
|
281
|
+
// (`<name>_supabase_database_password`) inline in each tool's <name>.tf — like the per-tool
|
|
282
|
+
// `<name>_vercel_project_id` — not a shared account credential gathered here. Set
|
|
283
|
+
// TF_VAR_<name>_supabase_database_password only when CREATING a project (ignored on import).
|
|
285
284
|
],
|
|
286
285
|
mcp: {
|
|
287
286
|
supabase: {
|
|
@@ -414,7 +413,7 @@ function tokensForTool(tool) {
|
|
|
414
413
|
}
|
|
415
414
|
|
|
416
415
|
// src/version.ts
|
|
417
|
-
var MODULE_REF = "v0.2.
|
|
416
|
+
var MODULE_REF = "v0.2.13";
|
|
418
417
|
var MODULE_SOURCE_BASE = "git::https://github.com/RTrentJones/greenlight.git//infra/modules";
|
|
419
418
|
function moduleSource(module, ref = MODULE_REF) {
|
|
420
419
|
return `${MODULE_SOURCE_BASE}/${module}?ref=${ref}`;
|
|
@@ -433,7 +432,7 @@ function emitToolTf(opts) {
|
|
|
433
432
|
const blocks = [];
|
|
434
433
|
const assumes = ["var.cloudflare_zone_id"];
|
|
435
434
|
if (useOci) assumes.push("var.cloudflare_account_id", "local.oci_compartment_id");
|
|
436
|
-
if (useSupabase) assumes.push("var.supabase_organization_id"
|
|
435
|
+
if (useSupabase) assumes.push("var.supabase_organization_id");
|
|
437
436
|
const ghcrOwner = (slug.split("/")[0] ?? "owner").toLowerCase();
|
|
438
437
|
blocks.push(
|
|
439
438
|
`# ${name} \u2014 ${lane}/${target}${useSupabase ? "/supabase" : ""}, emitted by \`greenlight add\`.
|
|
@@ -450,8 +449,17 @@ module "${name}_supabase" {
|
|
|
450
449
|
name = "${name}"
|
|
451
450
|
project_name = "${name}-db"
|
|
452
451
|
organization_id = var.supabase_organization_id
|
|
453
|
-
database_password = var
|
|
452
|
+
database_password = var.${name}_supabase_database_password
|
|
454
453
|
region = "us-east-1"
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
# Per-tool (the password is per Supabase PROJECT) \u2014 so a second data:supabase tool doesn't collide
|
|
457
|
+
# on a shared variable. Set TF_VAR_${name}_supabase_database_password only when CREATING a project;
|
|
458
|
+
# on import the module ignores it (the default placeholder is fine).
|
|
459
|
+
variable "${name}_supabase_database_password" {
|
|
460
|
+
type = string
|
|
461
|
+
sensitive = true
|
|
462
|
+
default = "import-placeholder" # ignored when importing an existing project
|
|
455
463
|
}`);
|
|
456
464
|
}
|
|
457
465
|
if (useVercel) {
|
|
@@ -603,9 +611,6 @@ function emitWrapperMainTf(opts) {
|
|
|
603
611
|
vars.push('variable "cloudflare_account_id" {\n type = string\n default = ""\n}');
|
|
604
612
|
if (need.has("supabase")) {
|
|
605
613
|
vars.push('variable "supabase_organization_id" { type = string }');
|
|
606
|
-
vars.push(
|
|
607
|
-
'variable "supabase_database_password" {\n type = string\n sensitive = true\n default = "import-placeholder" # ignored when importing an existing project\n}'
|
|
608
|
-
);
|
|
609
614
|
}
|
|
610
615
|
if (need.has("oci")) {
|
|
611
616
|
vars.push('variable "oci_tenancy_ocid" { type = string }');
|
|
@@ -1101,13 +1106,13 @@ function vendorDeps(vendorDir) {
|
|
|
1101
1106
|
}
|
|
1102
1107
|
function starterVerifyConfig(lane, target) {
|
|
1103
1108
|
const spec = lane === "mcp" ? "mode: 'mcp', expectTools: []" : "mode: 'api', checks: [{ path: '/', status: 200 }]";
|
|
1104
|
-
const logHint = target === "
|
|
1109
|
+
const logHint = target === "vercel" ? 'vercel logs "$GREENLIGHT_VERIFY_URL" --token "$VERCEL_API_TOKEN" 2>&1 | head -40 || true' : 'curl -sS -i "$GREENLIGHT_VERIFY_URL" 2>&1 | head -30 || true';
|
|
1105
1110
|
return `// Greenlight verify spec \u2014 edit to assert this tool's real contract.
|
|
1106
1111
|
export default {
|
|
1107
1112
|
${spec},
|
|
1108
1113
|
// Telemetry-into-verify: a shell command run ONLY when this report FAILS; its last ~50 lines
|
|
1109
|
-
// attach to the report so the agent/CI sees the "why" in-loop.
|
|
1110
|
-
// gate). Uncomment + adjust:
|
|
1114
|
+
// attach to the report so the agent/CI sees the "why" in-loop. $GREENLIGHT_VERIFY_URL is the
|
|
1115
|
+
// failing URL (no hard-coding). Best-effort (never fails the gate). Uncomment + adjust:
|
|
1111
1116
|
// logsOnFailure: '${logHint}',
|
|
1112
1117
|
};
|
|
1113
1118
|
`;
|
|
@@ -1463,7 +1468,9 @@ jobs:
|
|
|
1463
1468
|
env:
|
|
1464
1469
|
# Bypass Vercel Deployment Protection on the deployment URL (Vercel \u2192 project \u2192 Deployment
|
|
1465
1470
|
# Protection \u2192 Protection Bypass for Automation). Without it the gate asserts 401 (served).
|
|
1466
|
-
|
|
1471
|
+
# The SECRET is per-tool (the bypass value is per Vercel PROJECT) so two vercel tools never
|
|
1472
|
+
# collide; the env var the spec reads stays generic.
|
|
1473
|
+
VERCEL_AUTOMATION_BYPASS_SECRET: \${{ secrets.VERCEL_AUTOMATION_BYPASS_SECRET_${name.toUpperCase().replace(/-/g, "_")} }}
|
|
1467
1474
|
ANTHROPIC_API_KEY: \${{ secrets.ANTHROPIC_API_KEY }}
|
|
1468
1475
|
run: npx -y @rtrentjones/greenlight@latest verify --url "\${{ github.event.deployment_status.target_url }}" --spec verify/${name}.config.ts
|
|
1469
1476
|
`;
|
|
@@ -1480,8 +1487,10 @@ function nextVerifyConfig(name) {
|
|
|
1480
1487
|
// { mode: 'test', command: 'pnpm test' } + a tolerant deps-install step in greenlight-verify.yml.
|
|
1481
1488
|
const bypass = process.env.VERCEL_AUTOMATION_BYPASS_SECRET;
|
|
1482
1489
|
// Telemetry-into-verify: on a FAILED report, fetch the Vercel deployment's runtime logs and attach
|
|
1483
|
-
// the tail to the report (best-effort, never fails the gate).
|
|
1484
|
-
|
|
1490
|
+
// the tail to the report (best-effort, never fails the gate). $GREENLIGHT_VERIFY_URL is the exact
|
|
1491
|
+
// failing deployment URL (injected \u2014 no hard-coding); needs VERCEL_API_TOKEN in CI.
|
|
1492
|
+
const logsOnFailure =
|
|
1493
|
+
'vercel logs "$GREENLIGHT_VERIFY_URL" --token "$VERCEL_API_TOKEN" 2>&1 | head -40 || true';
|
|
1485
1494
|
const api = bypass
|
|
1486
1495
|
? {
|
|
1487
1496
|
mode: 'api',
|
|
@@ -1641,8 +1650,9 @@ Next:
|
|
|
1641
1650
|
greenlight secrets gather ${name} --repo ${slug} # GREENLIGHT_DISPATCH_TOKEN
|
|
1642
1651
|
The instance OCID is auto-resolved by the deploy workflow (by display name) \u2014 nothing to set.` : target === "vercel" ? `
|
|
1643
1652
|
Deploy is Vercel's git integration (no wrapper deploy). The tool's greenlight-verify.yml verifies
|
|
1644
|
-
each deployment (deployment_status). Optional
|
|
1645
|
-
|
|
1653
|
+
each deployment (deployment_status). Optional secrets on ${slug}:
|
|
1654
|
+
\xB7 VERCEL_AUTOMATION_BYPASS_SECRET_${name.toUpperCase().replace(/-/g, "_")} (Vercel \u2192 project \u2192 Deployment Protection \u2192 Bypass for Automation) \u2192 verify asserts 200, not 401
|
|
1655
|
+
\xB7 ANTHROPIC_API_KEY \u2192 enables the agent-web scenarios in verify/${name}.config.ts (absent \u2192 api gate alone)` : ""}`);
|
|
1646
1656
|
}
|
|
1647
1657
|
async function adoptStandalone(ctx) {
|
|
1648
1658
|
const { name, repoArg, lane, target, data, auth, envs, domain, reg, regPath } = ctx;
|
|
@@ -2245,7 +2255,9 @@ function attachFailureLogs(reports, specs, toolDir) {
|
|
|
2245
2255
|
cwd: toolDir,
|
|
2246
2256
|
timeout: 3e4,
|
|
2247
2257
|
encoding: "utf8",
|
|
2248
|
-
maxBuffer: 10 * 1024 * 1024
|
|
2258
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
2259
|
+
// Let the command target the exact failing URL without hard-coding it.
|
|
2260
|
+
env: { ...process.env, GREENLIGHT_VERIFY_URL: report.url }
|
|
2249
2261
|
});
|
|
2250
2262
|
const out = `${res.stdout ?? ""}${res.stderr ?? ""}`.trimEnd();
|
|
2251
2263
|
const tail = out.split("\n").slice(-LOG_TAIL_LINES).join("\n");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rtrentjones/greenlight",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.13",
|
|
4
4
|
"description": "Greenlight CLI — setup and lifecycle for the harness.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
"@anthropic-ai/sdk": "^0.69.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@rtrentjones/greenlight-loop": "0.2.4",
|
|
35
|
-
"@rtrentjones/greenlight-shared": "0.2.4",
|
|
36
34
|
"@rtrentjones/greenlight-adapters": "0.2.4",
|
|
37
|
-
"@rtrentjones/greenlight-
|
|
35
|
+
"@rtrentjones/greenlight-shared": "0.2.4",
|
|
36
|
+
"@rtrentjones/greenlight-verify": "0.2.4",
|
|
37
|
+
"@rtrentjones/greenlight-loop": "0.2.4"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "node scripts/copy-assets.mjs && tsup",
|