Add module-ci-action: raptor-driven CI for Facets modules repos#11
Merged
Conversation
New composite action, sibling to module-preview-action (which is unchanged
and remains the ftf-based action). It drives the raptor CLI for a modules
repo (modules/{intent}/{flavor}/{version}) in three event-derived modes:
- preview (pull_request): validate each changed module, then register an
unpublishable feature-branch preview pinned to the PR head commit; upsert
a PR comment when github_token is set.
- publish (push): upload each changed module and publish PREVIEW->PUBLISHED.
- cleanup (pull_request closed): delete a module's preview only when its
previewGitRef belongs to one of this PR's commits (ownership-checked).
Auth is via CONTROL_PLANE_URL/FACETS_USERNAME/FACETS_TOKEN env vars (raptor's
highest-priority auth; no non-interactive login). Preview's --feature-branch
flag ships in a parallel raptor PR, noted in the README version requirement.
Includes the action README, a numbered root README section, and a
lint-action workflow that parses action.yml and shellchecks every embedded
script.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Live e2e testing showed cleanup always skipped previews for brand-new modules. The Control Plane only populates previewGitRef on a PUBLISHED module that also has a preview sibling; a never-published module IS the preview (stage PREVIEW) and carries its owning commit in plain gitRef, with previewGitRef null — the common PR case. Cleanup now derives the owning commit per module row by stage: - stage PREVIEW -> .gitRef - stage PUBLISHED w/ preview sibling (.previewModuleId set) -> .previewGitRef - otherwise -> no preview slot, skip Prefers a PREVIEW row when both exist. Downstream SHA comparison against the PR's commits is unchanged, and absent/older provenance fields still degrade to a safe skip. README cleanup/single-preview-slot section updated to match. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Live testing showed `raptor delete iac-module REF --yes --force` deletes the PUBLISHED doc when a module has both published and preview versions — so cleanup on an in-place-update PR would delete the customer's live module. Delete now uses `raptor delete iac-module REF --stage PREVIEW --yes`, which targets only the preview doc (and errors if no preview exists). Dropped --force so the usage guard stays active and a genuinely in-use preview surfaces as a real error instead of being force-deleted; that failure is already recorded and gates the job. README version requirement updated to list --stage alongside --feature-branch and list-JSON provenance. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Optional input; when non-empty the install step downloads the raptor linux-amd64 binary from that exact URL (raptor_version ignored), otherwise behavior is unchanged. Escape hatch for testing/pre-release raptor builds and enterprise mirrors. Documented in the README inputs table. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ubuntu-latest runners ship neither terraform nor trivy, so raptor's
--dry-run validation hard-failed ("terraform is not installed") and the
security scan silently degraded. Added an install step (after mode
resolution, gated to skip cleanup mode, which needs neither):
- terraform: pinned via new input terraform-version (default 1.5.7 to match
module-preview-action), unzipped from releases.hashicorp.com to
/usr/local/bin.
- trivy: pinned via new input trivy-version (default 0.72.0), tarball from
aquasecurity/trivy releases to /usr/local/bin.
No third-party setup actions. README inputs table + requirements note
updated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
On PR merge, the push (publish) and pull_request-closed (cleanup) workflows fire concurrently. Publish re-uploads the preview at the merge SHA and mark-published consumes it, so cleanup is redundant — and racy: cleanup's ownership check (old PR-head SHA) and its --stage PREVIEW delete resolve at different times, so a bad interleaving can delete the merge-SHA preview the publish run just created and kill the publish. (Observed live: green publish + red cleanup on a merged PR.) Mode resolution now downgrades cleanup to a no-op when github.event.pull_request.merged == true, with a clear notice. Cleanup runs only for PRs closed without merging. Tooling-install gate tightened to preview/publish (skips the no-op too). README lifecycle table + single- preview-slot section updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Changed-file detection walks UP ancestors to the nearest facets.yaml, so a change under modules/x/y/1.0/templates/ maps to the module (was dropped by immediate-dirname mapping, shipping it unvalidated). - Cleanup re-fetches and re-verifies the owning SHA immediately before the --stage PREVIEW delete (TOCTOU); residual race documented in the README. - Reject pull_request_target explicitly (its base checkout yields an empty diff and wrong provenance) instead of treating it as pull_request. - Stop exporting CONTROL_PLANE_URL/FACETS_USERNAME/FACETS_TOKEN via GITHUB_ENV (leaked the token into every later step of the caller's job); set them as step-scoped env: on the raptor-invoking steps instead. - Guard force-push/rebase: verify github.event.before is reachable (rev-parse --verify) and fall back to the pushed commit's diff-tree, matching the all-zeros handling. - Cleanup jq tolerates a non-array payload and emits an explicit ::warning when a listed module resolves no owning commit, instead of silently claiming "no preview slot". - README: add the --git-ref raptor dependency to requirements. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…mp managed actions - Add release.yml: pushing a vX.Y.Z tag moves the major alias tag (v1) and creates the GitHub release; consumers pin module-ci-action@v1 instead of @master. - Document the versioning convention in the root and module-ci-action READMEs; example workflows now reference @v1. - Mark the ftf-based module-preview-action as deprecated (root README + its own README); module-ci-action is the current action. - Bump managed actions: actions/checkout v4 -> v7 (action steps, test workflows, README examples), actions/setup-python v5 -> v6. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A new composite GitHub Action,
module-ci-action/, that provides end-to-end CI for a Facets modules repository (modules/{intent}/{flavor}/{version}— each dir afacets.yaml+*.tf) using theraptorCLI (notftf, not Python).It is a sibling of the existing
module-preview-action/, which is left completely unchanged for ftf users. Consumed asFacets-cloud/github-actions/module-ci-action@master.Three event-derived modes
pull_requestopened/synchronize/reopenedraptor create iac-module -f <dir> --dry-run(validation gate), thenraptor create iac-module -f <dir> --feature-branch --git-ref <PR head sha>. Upserts a marker-based PR comment whengithub_tokenis set.pushraptor create iac-module -f <dir>thenraptor publish iac-module <intent>/<flavor>/<version>(metadata read fromfacets.yaml).pull_requestclosedpreviewGitReffromraptor get iac-module -o jsonand deletes the preview only if it belongs to one of this PR's commit SHAs (viagh api .../pulls/{n}/commits). Never touches a preview owned by another branch.modedefaults toauto(derives from the event) but can be set explicitly. Other inputs:control_plane_url/username/token(required),github_token,raptor_version(defaultlatest),all-modules(defaultfalse),path-prefix(default"").Notable design points
CONTROL_PLANE_URL/FACETS_USERNAME/FACETS_TOKENenv vars — raptor's highest-priority auth. No non-interactiveraptor loginexists, so none is attempted.--feature-branch: a new raptor flag shipping in a parallel raptor PR (not yet in any raptor ref — the baseiac-modulecommands don't have it). The README documents the raptor version requirement; thepreviewGitReffield cleanup reads is part of the same parallel work, and cleanup degrades gracefully (skips) when it's absent.HEAD== the pushed commit). Git remote URL auto-detects from the work tree.Validation performed
action.ymlparses as YAML (9 steps).bash -nand shellcheck (v0.10.0) with zero findings (intentional word-splitting annotated with scopeddisabledirectives)..github/workflows/test-module-ci.yamlthat re-runs exactly this validation in CI on any change undermodule-ci-action/**. A trueact-style run was intentionally not added: the action drives a live Control Plane (even--dry-runneeds an API client), so it can't authenticate in CI without secrets + a module fixture.🤖 Generated with Claude Code