Skip to content

feat(lockfile): migrate parser package from gh-actions-pin - #1

Merged
nodeselector merged 7 commits into
mainfrom
nodeselector/migrate-lockfile
Jun 8, 2026
Merged

feat(lockfile): migrate parser package from gh-actions-pin#1
nodeselector merged 7 commits into
mainfrom
nodeselector/migrate-lockfile

Conversation

@nodeselector

@nodeselector nodeselector commented Jun 7, 2026

Copy link
Copy Markdown
Collaborator

Repurposing this repo that housed the initial prototype of the CLI for shared library code to support lockfile parsing. Currently limited to go, but we'll need to support at least typescript for actions/languageservices.

Copilot AI review requested due to automatic review settings June 7, 2026 19:31
Migrate pkg/lockfile from github/gh-actions-pin (commit 6c98632,
branch nodeselector/fix-sha-pin-destruction) into standalone
multi-language repository.

Layout:
- go/pkg/lockfile/     — Go implementation (module github.com/github/actions-lockfile/go)
- schema/              — canonical lockfile JSON schema (single source of truth)
- testdata/            — shared test fixtures for all language implementations

Key decisions:
- Schema deduplication via go:generate (no duplicate JSON in Go tree)
- Shared testdata at root, symlinked into Go package for test resolution
- go 1.19 floor preserved for downstream consumer compatibility
- Security-boundary parser (uses.go) preserved byte-for-byte

Removes old prototype code (dev/, pkg/) and CLI test fixtures.

Source: github/gh-actions-lock@6c98632
Theme: lockfile-migration
Status: builds

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@nodeselector
nodeselector force-pushed the nodeselector/migrate-lockfile branch from 0415a21 to e22ea5f Compare June 7, 2026 19:33

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Not ready to approve

The published schema and uses: parsing need small but important correctness/security hardening fixes before the new lockfile contract is relied on by downstream tooling.

Pull request overview

This PR migrates the lockfile parser (and schema) into a standalone, multi-language actions-lockfile repository, restructuring the Go implementation into a go/ submodule and removing the prior CLI/resolver tooling and its workflow fixtures.

Changes:

  • Introduces a published JSON Schema (schema/lockfile-v0.0.1.json) plus Go-embedded schema generation and drift checks.
  • Adds a Go lockfile parsing library under go/pkg/lockfile (pins, action uses: parsing, schema enforcement, and position-aware errors).
  • Removes the previous CLI-oriented packages (pkg/pin, pkg/validate, pkg/resolver) and large workflow fixture corpora.
File summaries
File Description
testdata/workflows/tampered.yml Removed legacy workflow fixture used by old CLI validation tests.
testdata/workflows/sha-pinned.yml Removed legacy workflow fixture for SHA-pinned action cases.
testdata/workflows/path-action.yml Removed legacy fixture covering path-based action references.
testdata/workflows/nested-composite.yml Removed legacy fixture for composite recursion depth cases.
testdata/workflows/mixed.yml Removed legacy fixture for mixed uses types (local/docker/repo).
testdata/workflows/composite.yml Removed legacy fixture for composite action recursion.
testdata/workflows/basic.yml Removed legacy “basic” workflow fixture.
testdata/real-world/vercel-next.js-build_and_test.yml Removed large real-world workflow corpus fixture.
testdata/real-world/cli-cli-deployment.yml Removed large real-world workflow corpus fixture.
testdata/real-world/astral-sh-uv-ci.yml Removed large real-world workflow corpus fixture.
testdata/node_action.yml Adds a minimal node action fixture for action metadata parsing tests.
testdata/composite_action.yml Adds a minimal composite action fixture for nested uses: parsing tests.
schema/lockfile-v0.0.1.json Adds the published JSON Schema defining the lockfile format.
RELEASING.md Documents tagging/versioning, Go module floor, schema invariants, and dev workflow.
README.md Repositions the repo as a lockfile parser/schema home; updates usage/docs accordingly.
Makefile Simplifies targets to generation, linting, and testing for the Go submodule.
LICENSE Adds MIT license file.
pkg/validate/validate.go Removed old CLI validate command implementation.
pkg/validate/validate_test.go Removed integration tests tied to old CLI pin/validate flow.
pkg/resolver/resolver.go Removed GraphQL resolver used by the old CLI pin/validate workflow.
pkg/resolver/resolver_test.go Removed placeholder resolver test file.
pkg/pin/pin.go Removed old CLI pin command implementation.
pkg/lockfile/lockfile.go Removed old workflow-YAML mutator/dependencies: section implementation.
pkg/lockfile/lockfile_test.go Removed tests targeting the legacy workflow dependencies: section format.
pkg/actionmeta/actionmeta_test.go Removed legacy actionmeta tests (replaced by new package-local tests).
go/go.mod Adds Go submodule definition (go 1.19) and test dependencies.
go/go.sum Adds Go submodule sums for the new library tests.
go.mod Removes root Go module definition (repo now uses a Go submodule).
go.sum Removes root module sum file.
go/pkg/lockfile/doc.go Adds package docs emphasizing parsing as a security boundary.
go/pkg/lockfile/lockfile.go Adds core lockfile parser with version gating, canonicalization, and positioned errors.
go/pkg/lockfile/lockfile_test.go Adds unit tests for version handling, canonicalization, and position reporting.
go/pkg/lockfile/schema/lockfile-v0.0.1.json (Not changed; schema lives at repo root per RELEASING docs.)
go/pkg/lockfile/schema.go Exposes embedded schema via Schema() and hooks codegen.
go/pkg/lockfile/schema_gen.go Generated embedded schema constant for Go consumers.
go/pkg/lockfile/schema_test.go Ensures embedded schema matches root schema and enforcement invariants.
go/pkg/lockfile/internal/cmd/genschema/main.go Implements schema embedding code generator.
go/pkg/lockfile/pin.go Adds canonical pin parsing/canonicalization utilities and digest validation.
go/pkg/lockfile/pin_test.go Adds pin parsing and invalid-input test coverage.
go/pkg/lockfile/nwo.go Adds owner/repo splitting helper for repo-granularity behavior.
go/pkg/lockfile/nwo_test.go Adds tests for SplitNWO behavior and edge cases.
go/pkg/lockfile/uses.go Adds hardened uses: parsing for repository actions vs non-actions.
go/pkg/lockfile/uses_test.go Adds tests for uses: parsing, reusable workflow rejection, and SHA detection.
go/pkg/lockfile/version.go Adds semver-ish parsing utilities for action tag recommendation logic.
go/pkg/lockfile/version_test.go Adds tests for semver parsing/ordering/mutability logic.
go/pkg/lockfile/action_meta.go Moves action metadata parsing into the lockfile package (ParseActionMeta).
go/pkg/lockfile/action_meta_test.go Adds action metadata parsing tests using package-local fixtures.
dev/jobmsg/jobmsg.go Removed legacy runner job message builder tooling.
dev/harness-dotnet/Program.cs Removed legacy .NET runner harness tool.
dev/harness-dotnet/Harness.csproj Removed legacy .NET harness project file.
dev/harness-dotnet/.gitignore Removed legacy harness ignore file.
dev/fakelaunch/server.go Removed legacy fake Launch server used for runner integration demos.
.github/workflows/ci.yml Adds CI to run generate/lint/test across a Go version matrix.

Copilot's findings

Files not reviewed (2)

  • go/pkg/lockfile/internal/cmd/genschema/main.go: Language not supported
  • go/pkg/lockfile/schema_gen.go: Language not supported
  • Files reviewed: 49/53 changed files
  • Comments generated: 4

Note

Your feedback helps us improve the quality of this feature.
Please use 👍 or 👎 to tell us whether this assessment is correct.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread schema/lockfile-v0.0.1.json
Comment thread go/pkg/lockfile/lockfile.go Outdated
Comment thread go/pkg/lockfile/uses.go
Comment thread go/pkg/lockfile/uses.go
nodeselector and others added 5 commits June 7, 2026 14:46
setup-go looks for go.sum at repo root by default; our module
lives under go/.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tests

- Schema pin regex: enforce sha1=40 / sha256=64 hex digits (was unbounded)
- Parse() doc: clarify structural-only validation scope
- ParseActionRef: add isValidPath() for subdirectory charset + traversal guards
- Rename isValidOwnerOrRepo → isValidSegment (same charset, used for paths too)
- Add test: ref containing @ (foo/bar@a@b → ref=a@b)
- Add 5 path-rejection test cases (space, quotes, .., ., //)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…cies

Address staff + distinguished-engineer review feedback on the migrated
lockfile parser.

Security boundary (uses.go / doc.go):
- isValidSegment now rejects whole-segment "." and ".." (not just charset).
- Add isValidRef denylist for the @ref: rejects whitespace, quotes,
  backtick, backslash, and the ".." sequence (git-invalid, zero valid
  refs lost) so a ref cannot break out of a quoted literal or smuggle a
  traversal. Refs still contain "/", so downstream must percent-escape.
- ParseActionRef gates the ref via isValidRef. Tightened doc.go contract.

Breaking API change (lockfile.go):
- Rename File.Actions -> File.Dependencies to match the YAML key. The
  yaml:"dependencies" tag is unchanged, so the on-disk format is stable;
  only the Go field name changes. Downstream consumers must update field
  access.

Contract accuracy:
- Future-version error message is now tool-agnostic (no hardcoded
  gh-actions-pin upgrade command); ErrFutureVersion sentinel preserved.
- schema.go docstring corrected: the pin pattern constrains pin *values*
  (workflows/uses arrays), not dependencies map keys, so schema
  validation alone does not guarantee every dependency key is a pin.
- SemVer doc notes API stability (kept exported; consumer relies on it).

Tests: add 11 boundary-rejection cases (dot segments, quote/space/
backtick/backslash refs, ".." refs); keep foo/bar@a@b valid. Field
renames across lockfile_test, schema_test. Skip-on-missing testdata in
action_meta_test to match schema_test.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Downstream consumers (github/launch detached-lockfiles) must split a
reusable-workflow uses: ref (OWNER/REPO/.github/workflows/<name>.yml@ref)
into (nwo, subpath, ref) to derive that repo's lockfile path. Hand-rolling
the split with a last-`@` scan mis-parses refs that legitimately contain
`@` (e.g. a branch named "release@2024"), yielding a wrong path and a
silent enforcement downgrade. Centralize the split here, where the uses:
grammar and its telemetry-validated validation already live.

- Add exported ReusableWorkflowRef{Owner,Repo,Path,Ref,Raw} + NWO()/FullName()
  and ParseReusableWorkflowRef, the mirror of ParseActionRef for the shape
  ParseActionRef rejects. Same prefilters, first-`@` split, and security
  validation (charset, traversal, ref metacharacters).
- Extract the shared parse into splitUsesRef returning an unexported usesRef
  carrier, so ActionRef's "this is a repository action" contract is never
  briefly violated by an unclassified value.
- Tighten reusable-workflow classification: isReusableWorkflow now requires a
  single YAML file directly under .github/workflows/ (GitHub's actual
  grammar); nested paths like .github/workflows/sub/ci.yml are not reusable.
  ParseActionRef's rejection is preserved via the broader isWorkflowFile, so
  its behavior is unchanged and the two parsers remain mutually exclusive
  (locked in by a property test).
- ParseReusableWorkflowRef rejects local (./...) reusable workflows by design;
  IsLocalReusableWorkflow covers that shape.

Tests: full coverage for ParseReusableWorkflowRef incl. the ref-with-`@`
bug case, ref-with-`/`, nested rejection, injection/traversal rejection,
and a mutual-exclusion property test across both parsers.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
GitHub Advanced Security started work on behalf of nodeselector June 8, 2026 16:03 View session
GitHub Advanced Security finished work on behalf of nodeselector June 8, 2026 16:04
workflow_dispatch Release workflow with a patch/minor/major dropdown that
delegates to script/release. The script regenerates + drift-checks the tree,
runs the full build, computes the next go/vX.Y.Z from the latest tag, pushes
the tag, cuts a GitHub Release, and warms the module proxy. Runnable locally
(RELEASE_DRY_RUN=1 to preview). Guards against v2+ tags without a /vN module
path. Replaces local-only tagging.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
GitHub Advanced Security started work on behalf of nodeselector June 8, 2026 16:14 View session
GitHub Advanced Security finished work on behalf of nodeselector June 8, 2026 16:15
@nodeselector
nodeselector merged commit 6174943 into main Jun 8, 2026
9 of 10 checks passed
nodeselector added a commit that referenced this pull request Jul 8, 2026
feat(lockfile): migrate parser package from gh-actions-pin
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants