@theholocron/astromech 5.0.0-alpha.160 → 5.0.0-alpha.161

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.
Files changed (2) hide show
  1. package/dist/index.mjs +1 -1
  2. package/package.json +2 -2
package/dist/index.mjs CHANGED
@@ -140,7 +140,7 @@ var delivery_bundleSize_default$1 = "name: Audit the Bundle Size\n\non: # yamlli
140
140
  var delivery_deploy_default$1 = "name: Deploy\n\non: # yamllint disable-line rule:truthy\n workflow_call:\n inputs:\n type:\n description: \"Type of deployment: docs or storybook\"\n required: true\n type: string\n storybook-projects:\n description: >\n JSON array of { \"name\"?, \"workingDir\", \"outputDir\"? } objects for storybook deploys.\n Each is built via `pnpm -C <workingDir> build:storybook`. If \"name\" is provided the\n output is placed under `sandbox/<name>/`; omit \"name\" for single-repo deploys and the\n output lands directly in `sandbox/`.\n type: string\n required: false\n default: \"[]\"\n build-script:\n description: pnpm script that builds the Storybook static output (single storybook, type:storybook only)\n type: string\n required: false\n default: build:storybook\n output-dir:\n description: Directory where Storybook writes its static output (single storybook, type:storybook only)\n type: string\n required: false\n default: storybook-static\n\njobs:\n deploy:\n name: Deploy\n runs-on: ubuntu-latest\n permissions:\n contents: read\n pages: write\n id-token: write\n environment:\n name: github-pages\n url: ${{ steps.deployment.outputs.page_url }}\n steps:\n - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0\n name: Checkout repository\n\n - uses: theholocron/.github/.github/actions/setup@main\n name: Setup\n\n - name: Build docs site\n if: ${{ inputs.type == 'docs' }}\n run: pnpm -C docs build\n\n - name: Build Storybook projects\n if: ${{ inputs.storybook-projects != '[]' }}\n env:\n PROJECTS: ${{ inputs.storybook-projects }}\n run: |\n echo \"$PROJECTS\" | jq -c '.[]' | while IFS= read -r project; do\n workingDir=$(echo \"$project\" | jq -r '.workingDir')\n pnpm -C \"$workingDir\" build:storybook\n done\n\n - name: Build Storybook\n if: ${{ inputs.type == 'storybook' && inputs.storybook-projects == '[]' }}\n env:\n BUILD_SCRIPT: ${{ inputs.build-script }}\n run: pnpm run \"$BUILD_SCRIPT\"\n\n - name: Assemble site\n env:\n DEPLOY_TYPE: ${{ inputs.type }}\n PROJECTS: ${{ inputs.storybook-projects }}\n STORYBOOK_OUTPUT_DIR: ${{ inputs.output-dir }}\n run: |\n mkdir -p _site\n if [ \"$DEPLOY_TYPE\" = \"docs\" ]; then\n cp -r docs/dist/. _site/\n fi\n if [ \"$PROJECTS\" != \"[]\" ]; then\n echo \"$PROJECTS\" | jq -c '.[]' | while IFS= read -r project; do\n name=$(echo \"$project\" | jq -r '.name // \"\"')\n workingDir=$(echo \"$project\" | jq -r '.workingDir')\n outputDir=$(echo \"$project\" | jq -r '.outputDir // \"storybook-static\"')\n if [ -n \"$name\" ]; then\n target=\"_site/sandbox/${name}\"\n else\n target=\"_site/sandbox\"\n fi\n mkdir -p \"$target\"\n cp -r \"${workingDir}/${outputDir}/.\" \"$target/\"\n done\n elif [ \"$DEPLOY_TYPE\" = \"storybook\" ]; then\n mkdir -p _site/sandbox\n cp -r \"${STORYBOOK_OUTPUT_DIR}/.\" _site/sandbox/\n fi\n\n - uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1\n name: Upload pages artifact\n with:\n path: _site\n\n - uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5\n id: deployment\n name: Deploy to GitHub Pages\n";
141
141
  //#endregion
142
142
  //#region src/templates/reusable/delivery.previewCheck.yml
143
- var delivery_previewCheck_default$1 = "name: Preview Check\n\non: # yamllint disable-line rule:truthy\n workflow_call:\n inputs:\n preview-url:\n description: The PR's Vercel preview deployment URL, extracted from the triggering `deployment_status` event.\n required: true\n type: string\n sha:\n description: The deployed commit SHA — checked out explicitly, since GitHub evaluates which version of this workflow file to run from the default branch for a deployment_status event (unlike push/pull_request), and actions/checkout defaults to that same ref absent an explicit override.\n required: true\n type: string\n cwd:\n description: Directory to run the check from — the opted-in package's own directory in a monorepo. Defaults to the repo root.\n required: false\n type: string\n default: \".\"\n vercel-project:\n description: >\n Expected Vercel project id/name the preview URL must resolve\n to (verified live via Vercel's API) before\n VERCEL_PROTECTION_BYPASS_SECRET is ever attached to a request\n (holocron#1032 review) — a bare *.vercel.app hostname proves\n nothing on its own, since anyone can register their own\n Vercel project. Omitted → the bypass secret is never\n attached, regardless of whether it's configured.\n required: false\n type: string\n default: \"\"\n secrets:\n VERCEL_TOKEN:\n description: >\n Required alongside vercel-project to verify deployment\n ownership via Vercel's API (read-only use here). Not required\n when vercel-project is omitted.\n required: false\n VERCEL_PROTECTION_BYPASS_SECRET:\n description: >\n Vercel's \"Protection Bypass for Automation\" secret for the\n target project (holocron#1030) — sent as the\n x-vercel-protection-bypass header so this check's request\n isn't redirected to Vercel's own SSO login by Deployment\n Protection, which is on by default for Preview deployments.\n Optional: a check against a URL with protection disabled (or\n a provider other than Vercel) needs nothing here.\n required: false\n\njobs:\n preview-check:\n name: Run monitoring checks against the preview deployment\n permissions:\n contents: read\n runs-on: ubuntu-latest\n timeout-minutes: 15\n steps:\n - name: Validate the preview URL\n id: validate\n env:\n CANDIDATE: ${{ inputs.preview-url }}\n run: |\n # `preview-url` comes from the triggering deployment_status\n # event's environment_url -- set by whoever created that\n # deployment status, not necessarily this repo's own\n # delivery.previewDeploy job (anyone with `deployments: write`\n # could create one directly via the API). Validated here,\n # independently of the event's origin, before this runner\n # ever issues an HTTP request to it (the monitoring check\n # below): without this, a crafted environment_url could point\n # the runner at an internal or attacker-controlled host\n # (SSRF) instead of a real Vercel preview. Forwarding the\n # re-serialized `url.href` rather than the raw input also\n # closes off argument injection through embedded whitespace\n # or shell metacharacters -- a string that parses can't carry\n # either.\n host=$(node -e 'try { process.stdout.write(new URL(process.argv[1]).hostname) } catch { process.exit(1) }' \"$CANDIDATE\") || host=\"\"\n if [[ \"$host\" != *.vercel.app ]]; then\n echo \"::error::preview-url '$CANDIDATE' does not parse to a *.vercel.app host (parsed host: '${host:-<unparseable>}')\"\n exit 1\n fi\n url=$(node -e 'const u = new URL(process.argv[1]); if (u.protocol !== \"https:\") process.exit(1); process.stdout.write(u.href)' \"$CANDIDATE\") || {\n echo \"::error::preview-url '$CANDIDATE' did not parse to an https:// URL\"\n exit 1\n }\n echo \"url=$url\" >> \"$GITHUB_OUTPUT\"\n\n - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0\n name: Checkout repository\n with:\n ref: ${{ inputs.sha }}\n # This checks out and runs a PR's own holocron.config.ts —\n # untrusted until reviewed. Never leave a credential sitting\n # in .git/config for that code to read and exfiltrate; no\n # later step in this job needs to push or pull authenticated.\n persist-credentials: false\n\n - uses: theholocron/.github/.github/actions/setup@main\n name: Setup\n\n - name: Resolve monitoring checks\n id: resolve\n # Untrusted: loads and runs a PR's own holocron.config.ts, same\n # as the checkout above. No secrets in this step's env at all\n # (holocron#1032 review) -- VERCEL_TOKEN and\n # VERCEL_PROTECTION_BYPASS_SECRET live only on the step below,\n # which never loads this repo's config and so never runs a\n # single line of PR-authored code.\n uses: theholocron/.github/.github/actions/holocron@main\n with:\n command: monitoring resolve-checks\n args: --cwd=${{ inputs.cwd }} --out=${{ runner.temp }}/monitoring-checks.json\n\n - name: Verify project and run monitoring checks\n env:\n # Read directly by `monitoring run-resolved`\n # (packages/cli/src/cli.ts) -- not part of the CLI's own\n # `--token`-resolution chain, since neither is a vendor API\n # credential this command calls anything with: VERCEL_TOKEN\n # only verifies, read-only, that the preview URL resolves to\n # vercel-project before VERCEL_PROTECTION_BYPASS_SECRET (a\n # plain header forwarded as-is) is ever attached. The command\n # itself never attaches the bypass header when vercel-project\n # is empty, regardless of whether these secrets are\n # configured -- never attached to an unverified URL.\n VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}\n VERCEL_PROTECTION_BYPASS_SECRET: ${{ secrets.VERCEL_PROTECTION_BYPASS_SECRET }}\n uses: theholocron/.github/.github/actions/holocron@main\n with:\n command: monitoring run-resolved\n args: --checks-file=${{ runner.temp }}/monitoring-checks.json --vercel-project=${{ inputs.vercel-project }} ${{ steps.validate.outputs.url }}\n";
143
+ var delivery_previewCheck_default$1 = "name: Preview Check\n\non: # yamllint disable-line rule:truthy\n workflow_call:\n inputs:\n preview-url:\n description: The PR's Vercel preview deployment URL, extracted from the triggering `deployment_status` event.\n required: true\n type: string\n sha:\n description: The deployed commit SHA — checked out explicitly, since GitHub evaluates which version of this workflow file to run from the default branch for a deployment_status event (unlike push/pull_request), and actions/checkout defaults to that same ref absent an explicit override.\n required: true\n type: string\n cwd:\n description: Directory to run the check from — the opted-in package's own directory in a monorepo. Defaults to the repo root.\n required: false\n type: string\n default: \".\"\n vercel-project:\n description: >\n Expected Vercel project id/name the preview URL must resolve\n to (verified live via Vercel's API) before\n VERCEL_PROTECTION_BYPASS_SECRET is ever attached to a request\n (holocron#1032 review) — a bare *.vercel.app hostname proves\n nothing on its own, since anyone can register their own\n Vercel project. Omitted → the bypass secret is never\n attached, regardless of whether it's configured.\n required: false\n type: string\n default: \"\"\n secrets:\n VERCEL_TOKEN:\n description: >\n Required alongside vercel-project to verify deployment\n ownership via Vercel's API (read-only use here). Not required\n when vercel-project is omitted.\n required: false\n VERCEL_PROTECTION_BYPASS_SECRET:\n description: >\n Vercel's \"Protection Bypass for Automation\" secret for the\n target project (holocron#1030) — sent as the\n x-vercel-protection-bypass header so this check's request\n isn't redirected to Vercel's own SSO login by Deployment\n Protection, which is on by default for Preview deployments.\n Optional: a check against a URL with protection disabled (or\n a provider other than Vercel) needs nothing here.\n required: false\n\njobs:\n preview-check:\n name: Run monitoring checks against the preview deployment\n permissions:\n contents: read\n # Both read-only, needed by the \"Resolve author trust\" step\n # below: pull-requests to find which PR `inputs.sha` belongs to,\n # and the collaborators/permission lookup (Metadata: read on a\n # PAT, already covered by contents) that step makes against the\n # real PR author.\n pull-requests: read\n runs-on: ubuntu-latest\n timeout-minutes: 15\n steps:\n - name: Validate the preview URL\n id: validate\n env:\n CANDIDATE: ${{ inputs.preview-url }}\n run: |\n # `preview-url` comes from the triggering deployment_status\n # event's environment_url -- set by whoever created that\n # deployment status, not necessarily this repo's own\n # delivery.previewDeploy job (anyone with `deployments: write`\n # could create one directly via the API). Validated here,\n # independently of the event's origin, before this runner\n # ever issues an HTTP request to it (the monitoring check\n # below): without this, a crafted environment_url could point\n # the runner at an internal or attacker-controlled host\n # (SSRF) instead of a real Vercel preview. Forwarding the\n # re-serialized `url.href` rather than the raw input also\n # closes off argument injection through embedded whitespace\n # or shell metacharacters -- a string that parses can't carry\n # either.\n host=$(node -e 'try { process.stdout.write(new URL(process.argv[1]).hostname) } catch { process.exit(1) }' \"$CANDIDATE\") || host=\"\"\n if [[ \"$host\" != *.vercel.app ]]; then\n echo \"::error::preview-url '$CANDIDATE' does not parse to a *.vercel.app host (parsed host: '${host:-<unparseable>}')\"\n exit 1\n fi\n url=$(node -e 'const u = new URL(process.argv[1]); if (u.protocol !== \"https:\") process.exit(1); process.stdout.write(u.href)' \"$CANDIDATE\") || {\n echo \"::error::preview-url '$CANDIDATE' did not parse to an https:// URL\"\n exit 1\n }\n echo \"url=$url\" >> \"$GITHUB_OUTPUT\"\n\n - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0\n name: Checkout repository\n with:\n ref: ${{ inputs.sha }}\n # This checks out and runs a PR's own holocron.config.ts —\n # untrusted until reviewed. Never leave a credential sitting\n # in .git/config for that code to read and exfiltrate; no\n # later step in this job needs to push or pull authenticated.\n persist-credentials: false\n\n - uses: theholocron/.github/.github/actions/setup@main\n name: Setup\n\n - name: Resolve author trust\n id: trust\n env:\n # Ambient, always-available -- no new secret. Only used for\n # two read-only lookups, both within what this token already\n # has by default.\n GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n SHA: ${{ inputs.sha }}\n run: |\n # Deliberately NOT a value carried in through the\n # deployment's own `payload` field (sourcery review on\n # #1058's first attempt): that field is attacker-controlled\n # by anyone with `deployments: write` -- same precondition\n # already needed to create a deployment_status event at all\n # -- so trusting whatever it claims would let that same\n # attacker forge payload.collaborator_permission = \"admin\"\n # on their own crafted deployment and unlock the bypass\n # secret regardless of who actually authored the code. This\n # step derives trust itself, from data it verifies\n # independently: which real PR `inputs.sha` belongs to, and\n # that PR's real author's current push-access level -- an\n # attacker can't forge either without already having\n # genuine write access to this repo.\n #\n # First attempt used\n # github.event.pull_request.author_association instead, and\n # separately turned out to be wrong for a different reason:\n # that field only reports MEMBER for a *publicly visible* org\n # membership, so a maintainer with private org membership\n # reads as CONTRIBUTOR and would wrongly fail-closed on their\n # own PRs (confirmed live on this exact repo, holocron#1057\n # follow-up). This lookup has neither problem: it reflects\n # real access -- direct collaborator, team membership, or\n # org default -- independent of any profile visibility\n # setting, and needs only \"Pull requests: read\" plus the\n # baseline \"Metadata: read\" every token already has.\n #\n # No PR found for this SHA, or no login on it -> \"none\" ->\n # untrusted. admin/maintain/write are the three roles GitHub\n # itself treats as push-capable. Missing or unrecognized ->\n # untrusted (fail-closed): an absent credential is safer\n # than a wrongly granted one.\n author=$(gh api \"repos/${GITHUB_REPOSITORY}/commits/${SHA}/pulls\" --jq '(.[0] // {}) | .user.login // empty' 2>/dev/null) || author=\"\"\n permission=\"none\"\n if [ -n \"$author\" ]; then\n permission=$(gh api \"repos/${GITHUB_REPOSITORY}/collaborators/${author}/permission\" --jq '.permission // \"none\"' 2>/dev/null) || permission=\"none\"\n fi\n case \"$permission\" in\n admin | maintain | write) trusted=true ;;\n *) trusted=false ;;\n esac\n echo \"trusted=$trusted\" >> \"$GITHUB_OUTPUT\"\n\n - name: Resolve monitoring checks\n id: resolve\n # Untrusted: loads and runs a PR's own holocron.config.ts, same\n # as the checkout above. No secrets in this step's env at all\n # (holocron#1032 review) -- VERCEL_TOKEN and\n # VERCEL_PROTECTION_BYPASS_SECRET live only on the step below,\n # which never loads this repo's config and so never runs a\n # single line of PR-authored code.\n uses: theholocron/.github/.github/actions/holocron@main\n with:\n command: monitoring resolve-checks\n args: --cwd=${{ inputs.cwd }} --out=${{ runner.temp }}/monitoring-checks.json\n\n - name: Verify project and run monitoring checks\n env:\n # Read directly by `monitoring run-resolved`\n # (packages/cli/src/cli.ts) -- not part of the CLI's own\n # `--token`-resolution chain, since neither is a vendor API\n # credential this command calls anything with: VERCEL_TOKEN\n # only verifies, read-only, that the preview URL resolves to\n # vercel-project before VERCEL_PROTECTION_BYPASS_SECRET (a\n # plain header forwarded as-is) is ever attached. The command\n # itself never attaches the bypass header when vercel-project\n # is empty, regardless of whether these secrets are\n # configured -- never attached to an unverified URL.\n #\n # Both gated on `steps.trust.outputs.trusted` (holocron#1057):\n # confirmed live that Vercel forwards this header straight\n # through to the deployed function, so an untrusted PR's own\n # code could read and exfiltrate it off its own incoming\n # request. An untrusted deployment gets neither secret.\n VERCEL_TOKEN: ${{ steps.trust.outputs.trusted == 'true' && secrets.VERCEL_TOKEN || '' }}\n VERCEL_PROTECTION_BYPASS_SECRET: ${{ steps.trust.outputs.trusted == 'true' && secrets.VERCEL_PROTECTION_BYPASS_SECRET || '' }}\n uses: theholocron/.github/.github/actions/holocron@main\n with:\n command: monitoring run-resolved\n # vercel-project is NOT gated on trust (sourcery review on\n # #1058's first attempt) -- it isn't a secret, and clearing\n # it for an untrusted deployment would make\n # resolveVercelBypassHeaders treat \"no project given\" as\n # trivially verified (its early-return for an omitted\n # project), skipping ownership verification entirely rather\n # than failing. Always passing the real project here means\n # an untrusted deployment instead hits the \"project given\n # but no token\" branch -- VERCEL_TOKEN is empty above --\n # which fails the check outright, before ever issuing the\n # request, rather than letting an unverified host's response\n # (e.g. a 3xx redirect a status-less assertion wouldn't\n # catch) report green.\n args: --checks-file=${{ runner.temp }}/monitoring-checks.json --vercel-project=${{ inputs.vercel-project }} ${{ steps.validate.outputs.url }}\n";
144
144
  //#endregion
145
145
  //#region src/templates/reusable/delivery.previewDeploy.yml
146
146
  var delivery_previewDeploy_default$1 = "name: Preview Deploy\n\non: # yamllint disable-line rule:truthy\n workflow_call:\n inputs:\n cwd:\n description: Directory to run the delivery.previewDeploy task from — the opted-in package's own directory in a monorepo. Defaults to the repo root.\n required: false\n type: string\n default: \".\"\n secrets:\n VERCEL_TOKEN:\n required: false\n HOLOCRON_DEPLOYMENTS_TOKEN:\n description: >\n A dedicated fine-grained PAT (Deployments: read/write only — see\n docs/tokens.md), not the default GITHUB_TOKEN — GitHub does not\n start a new workflow run for a deployment_status event created\n using a run's own GITHUB_TOKEN, which would make a\n deployment_status-triggered check (e.g. delivery.previewCheck)\n silently never fire. No existing HOLOCRON_<FEATURE>_TOKEN carries\n the Deployments permission, so `secrets: inherit` on the thin\n caller forwards nothing for this unless a repo/org secret\n literally named HOLOCRON_DEPLOYMENTS_TOKEN has been provisioned.\n required: false\n\njobs:\n # Two jobs, deliberately not one: \"report\" never checks out the repo at\n # all, so it never runs a single line of this PR's own code. \"deploy\"\n # does — it has to, to build and stage the preview — and runs with\n # VERCEL_TOKEN present for that (tracked as a residual risk, #1020: the\n # build step still runs this monorepo's own PR-affectable CLI build,\n # pre-review). Without the split, a malicious build/stage script could\n # persist a `gh` shim onto $GITHUB_PATH (or similar runner-state\n # tampering) that a LATER step in the SAME job — the one that finally\n # gets GH_TOKEN — would then execute instead of the real `gh` CLI,\n # stealing that token too. Separate jobs run on separate, fresh\n # runners; \"report\" has nothing of the first job's runner state to\n # inherit.\n deploy:\n name: Deploy preview\n runs-on: ubuntu-latest\n # Setup/build/stage, plus the deploy capability's own\n # wait-for-ready polling (up to 10 minutes by itself) — 10 would kill\n # this before that polling could even finish.\n timeout-minutes: 20\n permissions:\n contents: read\n outputs:\n url: ${{ steps.extract.outputs.url }}\n steps:\n - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0\n name: Checkout repository\n with:\n # The PR's exact head SHA, not the default pull_request\n # merge-commit ref — what gets built and deployed must be the\n # exact commit the PR actually points at.\n ref: ${{ github.event.pull_request.head.sha }}\n persist-credentials: false\n\n - uses: theholocron/.github/.github/actions/setup@main\n name: Setup\n\n - name: Check deploy credentials are available\n id: creds\n env:\n VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}\n run: |\n # `secrets` isn't valid in a step `if:` (actionlint-enforced) —\n # a fork PR never receives this secret, so the deploy step below\n # skips cleanly on an empty token instead of failing on a\n # missing credential. That skip is silent to the fork\n # contributor -- no preview, no explanation why -- tracked\n # as #1027 rather than fixed here (the real fix needs either\n # a status comment or a maintainer-gated trusted-deploy path,\n # not a quick addition to this step).\n echo \"available=$([ -n \"$VERCEL_TOKEN\" ] && echo true || echo false)\" >> \"$GITHUB_OUTPUT\"\n\n - name: Deploy preview\n id: deploy\n if: ${{ steps.creds.outputs.available == 'true' }}\n env:\n VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}\n uses: theholocron/.github/.github/actions/holocron@main\n with:\n command: run delivery.previewDeploy\n args: --cwd=${{ inputs.cwd }}\n\n - name: Extract and validate the preview URL\n id: extract\n # Only after a real deploy — false both when the step above\n # failed and when it skipped cleanly (fork PR, no credential).\n if: ${{ steps.deploy.outcome == 'success' }}\n env:\n LOG_FILE: ${{ steps.deploy.outputs.log-file }}\n run: |\n # A loose https://\\S+ grab would match whatever text follows an\n # attacker-chosen URL this log happens to contain; grabbing\n # candidate text here and separately requiring the PARSED\n # hostname end in .vercel.app (below) closes that regardless of\n # how the candidate text is shaped — e.g. a userinfo trick like\n # \"https://x.vercel.app@127.0.0.1/\" would satisfy almost any\n # hand-written regex character class while actually parsing to\n # host 127.0.0.1, which a naive regex-only check already missed\n # once.\n candidate=$(grep -oE 'https://[^[:space:]\"]+' \"$LOG_FILE\" | tail -1)\n if [ -z \"$candidate\" ]; then\n echo \"::error::deploy succeeded but no https:// URL was found in its output\"\n exit 1\n fi\n host=$(node -e 'try { process.stdout.write(new URL(process.argv[1]).hostname) } catch { process.exit(1) }' \"$candidate\") || host=\"\"\n if [[ \"$host\" != *.vercel.app ]]; then\n echo \"::error::extracted URL '$candidate' does not parse to a *.vercel.app host (parsed host: '${host:-<unparseable>}')\"\n exit 1\n fi\n echo \"url=$candidate\" >> \"$GITHUB_OUTPUT\"\n\n report:\n name: Report deployment status\n needs: deploy\n if: ${{ needs.deploy.outputs.url != '' }}\n runs-on: ubuntu-latest\n timeout-minutes: 5\n permissions:\n deployments: write\n steps:\n - name: Create GitHub deployment and report status\n env:\n # gh reads GH_TOKEN as its auto-auth env var by its own\n # convention -- the secret feeding it is named\n # HOLOCRON_DEPLOYMENTS_TOKEN, matching this org's\n # HOLOCRON_<FEATURE>_TOKEN naming (docs/tokens.md).\n GH_TOKEN: ${{ secrets.HOLOCRON_DEPLOYMENTS_TOKEN }}\n # The PR's head BRANCH, not its SHA — GitHub's PR \"Environments\"\n # widget associates a Deployment with a PR by matching `ref` to\n # the PR's own branch name, not by SHA. GitHub resolves the\n # branch to whatever commit it points to AT CREATION TIME,\n # though, which is a separate moment from the deploy job's own\n # checkout (below, SHA) -- cross-checked after creation rather\n # than assumed.\n REF: ${{ github.event.pull_request.head.ref }}\n # The exact commit the deploy job checked out and built,\n # captured from the same frozen event payload this whole run\n # was triggered by -- stays constant for the run's lifetime\n # even if the PR branch itself moves while this job is running.\n SHA: ${{ github.event.pull_request.head.sha }}\n URL: ${{ needs.deploy.outputs.url }}\n run: |\n if [ -z \"$GH_TOKEN\" ]; then\n echo \"::error::HOLOCRON_DEPLOYMENTS_TOKEN secret is not set -- posting this status with the default GITHUB_TOKEN would not trigger a deployment_status-triggered check\"\n exit 1\n fi\n\n post_status() {\n gh api \"repos/${GITHUB_REPOSITORY}/deployments/${deploy_id}/statuses\" \\\n --method POST --field state=\"$1\" --field environment_url=\"$URL\" >/dev/null\n }\n latest_status() {\n gh api \"repos/${GITHUB_REPOSITORY}/deployments/${deploy_id}/statuses\" --jq '.[0].state // empty' 2>/dev/null\n }\n # A deployment this very run may have already created\n # server-side on an earlier attempt whose client-side response\n # got lost (e.g. a dropped connection) -- reused instead of\n # creating a second one, which would leave the first\n # permanently pending (nothing ever posts its status). Scoped\n # to the last 2 minutes so an OLDER deployment for the same\n # ref/environment (a previous, unrelated run) is never\n # mistaken for this one.\n find_recent_deployment() {\n gh api \"repos/${GITHUB_REPOSITORY}/deployments\" --method GET -f ref=\"$REF\" -f environment=Preview --jq '\n [.[] | select((now - (.created_at | fromdateiso8601)) < 120)] | sort_by(.created_at) | last | .id // empty' 2>/dev/null\n }\n\n # jq, not a hand-built string -- a branch name containing a\n # literal double quote (git allows it; GitHub's branch-naming\n # rules don't forbid it either) would otherwise break out of a\n # printf-constructed JSON string and produce an invalid payload\n # gh api can't send.\n payload=$(jq -n --arg ref \"$REF\" '{\n ref: $ref,\n environment: \"Preview\",\n description: \"Vercel Preview (file deploy)\",\n production_environment: false,\n auto_merge: false,\n required_contexts: []\n }')\n deploy_id=\"\"\n for attempt in 1 2 3; do\n deploy_id=$(find_recent_deployment)\n if [ -n \"$deploy_id\" ]; then\n echo \"reusing deployment ${deploy_id} created by an earlier attempt of this run\" >&2\n break\n fi\n deploy_id=$(echo \"$payload\" | gh api \"repos/${GITHUB_REPOSITORY}/deployments\" --method POST --input - | jq -r '.id // empty')\n if [ -n \"$deploy_id\" ]; then break; fi\n echo \"deployment creation failed (attempt ${attempt}/3) -- retrying...\" >&2\n sleep 5\n done\n if [ -z \"$deploy_id\" ]; then\n echo \"::error::failed to create a GitHub deployment after 3 attempts -- Vercel already has the preview, but nothing will report or check it\"\n exit 1\n fi\n\n # `ref` resolves to the branch's CURRENT tip at creation time --\n # only guaranteed to be the commit this job actually built if\n # the branch hasn't moved since the triggering push. A push to\n # the same PR while this job was still running would otherwise\n # silently associate the preview URL (built from the OLD\n # commit) with the NEW commit's deployment. A newer workflow\n # run already covers that new commit (cancel-in-progress:\n # false queues rather than cancels), so failing this stale one\n # loses nothing.\n deployed_sha=$(gh api \"repos/${GITHUB_REPOSITORY}/deployments/${deploy_id}\" --jq '.sha // empty')\n if [ \"$deployed_sha\" != \"$SHA\" ]; then\n echo \"::error::deployment ${deploy_id} resolved to ${deployed_sha}, not the deployed commit ${SHA} -- the PR branch moved while this job was running; a newer run already covers the new commit\"\n exit 1\n fi\n\n for attempt in 1 2 3; do\n if post_status success; then\n exit 0\n fi\n # The POST may have actually succeeded server-side even though\n # this client call reported failure (e.g. a dropped connection\n # after GitHub processed it) — checked before retrying, so a\n # transient client-side error never posts a second success and\n # fires delivery.previewCheck twice for the same preview.\n if [ \"$(latest_status)\" = \"success\" ]; then\n exit 0\n fi\n echo \"status POST failed (attempt ${attempt}/3) for deployment ${deploy_id} -- retrying...\" >&2\n sleep 5\n done\n\n # Exhausted retries — one last attempt to mark the deployment\n # failed rather than leaving it permanently \"pending\" in GitHub's\n # UI; best-effort, its own failure doesn't change this step's\n # already-failed outcome.\n post_status error || true\n echo \"::error::failed to post a success status for deployment ${deploy_id} after 3 attempts -- marked it failed instead of leaving it pending\"\n exit 1\n";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theholocron/astromech",
3
- "version": "5.0.0-alpha.160",
3
+ "version": "5.0.0-alpha.161",
4
4
  "description": "The Holocron task runner — one task manifest drives `holocron run`, `holocron run ci`, the CI workflows, package.json scripts, linters, and required checks.",
5
5
  "keywords": [
6
6
  "ci",
@@ -48,7 +48,7 @@
48
48
  "@theholocron/fs-utils": "^1.15.1",
49
49
  "@theholocron/json-utils": "^1.15.1",
50
50
  "@theholocron/pkg-utils": "^1.15.1",
51
- "@theholocron/datapad": "5.0.0-alpha.160"
51
+ "@theholocron/datapad": "5.0.0-alpha.161"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@commitlint/config-conventional": "^21.2.3",