Skip to content

Create change-management-check composite action - #1712

Merged
tvc-jeffwelling merged 9 commits into
mainfrom
feat/IP-4105-change-management-check
Oct 21, 2026
Merged

tvc-jeffwelling merged 9 commits into
mainfrom
feat/IP-4105-change-management-check

Conversation

@tvc-jeffwelling

@tvc-jeffwelling tvc-jeffwelling commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

New composite action change-management-check: fails the check when a change-management section in the PR body (Testing evidence, Success / failure criteria, Rollback plan) is empty or missing. The failure message names the empty sections and links the Standard.

The action reads only the PR body from the event payload. No checkout, no PR code execution, no API calls, read-only scope.

Exemptions are the workflow's job: the caller skips the check step for renovate/* head branches (step condition) and for docs-only or dev-only changes (dorny/paths-filter with predicate-quantifier: some-with-excludes). Heading names and strip-lines come from the caller's inputs, so one action serves repos with different PR templates.

Inputs: sections (required), strip-lines, standard-url.

Tests: node --test, 26 cases, with the three production-path PR templates as fixtures.

Ships with a major changeset, so the first release is change-management-check/1.0.0 with the moving change-management-check/v1 tag. Consumers pin @change-management-check/v1, same as do-not-merge@do-not-merge/v1.

Part 1 of IP-4105 (epic IP-3990): the per-repo workflows and the required-check wiring follow.

Ticket: https://smartcontract-it.atlassian.net/browse/IP-4105

Fails the check when a Testing evidence, Success / failure criteria, or Rollback plan section in the PR body is empty or missing. Exempt: Renovate branches, docs-only PRs, dev-only PRs.
@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

🦋 Changeset is good to go

Latest commit: e2aba6b

We got this.

Not sure what this means? Click here to learn what changesets are.

Comment thread actions/change-management-check/scripts/check.js Fixed
Strip HTML comments with an indexOf loop instead of a regex (CodeQL js/incomplete-multi-character-sanitization). An unterminated comment now drops the rest of the body, matching how GitHub renders it. Call core.summary.write(); addRaw alone leaves the buffer unwritten. Treat an explicit empty docs-paths or head-prefixes input as no exemption instead of falling back to a default.
Same matching behavior, one loop, no index arithmetic. Adds a test for the ? token.
Replace the token loop with a replace() over an ordered token regex and a lookup map. Same behavior, fewer lines.
Adds the Standard link, a copy-paste workflow, the inputs table, the exemption rules, and the known limitations.
The old heading regex backtracked super-linearly on a hostile body line: 2.5 s for a 4 KB line, hours extrapolated for 64 KB. The new one is linear and handles CommonMark closing hashes. A section now ends at a heading of the same or higher level, or at a configured alias, so subheadings no longer read as empty.
Avoids the 0.0.0 placeholder. The major changeset still takes the first release to 1.0.0.
@tvc-jeffwelling
tvc-jeffwelling marked this pull request as ready for review October 21, 2026 16:23
@tvc-jeffwelling
tvc-jeffwelling requested a review from a team as a code owner October 21, 2026 16:23
Comment on lines +132 to +149
async function listFiles(github, context) {
const { owner, repo } = context.repo;
const pull_number = context.payload.pull_request.number;
const files = [];
// The API caps at 3000 files; 30 pages of 100.
for (let page = 1; page <= 30; page++) {
const { data } = await github.rest.pulls.listFiles({
owner,
repo,
pull_number,
per_page: 100,
page,
});
files.push(...data.map((file) => file.filename));
if (data.length < 100) break;
}
return files;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think you're better off doing something different than pulling modified files, and hardcoding paths to ignore.

My personal recommendation would be have this action check the PR description, and use some other dedicated action to determine path changes in the workflow: https://github.com/dorny/paths-filter

This action could then be skipped at the workflow level if path changes aren't included.


This is a matter of opinion though, so happy to approve if you'd still prefer it done as part of this action.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done, thanks. The action now checks only the PR body; it reads the body from the event payload and nothing else. The workflow decides applicability: dorny/paths-filter for the docs and dev paths, and a step condition for the renovate prefix. The docs-paths, dev-paths, and head-prefixes inputs are gone. The README example shows the wiring.

Comment on lines +19 to +20
pull_request_target:
types: [opened, edited, synchronize, reopened, ready_for_review]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should almost never use pull_request_target events. Why do you need this over pull_request events?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Two reasons. First, tamper resistance: the check will be required, so a PR must not be able to alter its own gate. With pull_request_target the workflow and the action (pinned to the change-management-check/v1 tag) come from the base branch; with pull_request the workflow comes from the PR head, so a PR could rename the job or edit the workflow to pass. Second, fork PRs: with pull_request a fork PR's workflow waits for maintainer approval, and the required check shows Expected until then; pull_request_target runs without that step. The usual pull_request_target risk does not apply here: no checkout of PR code, no secrets, the only permission is pull-requests: read (used by the path filter), and the action itself reads only the event payload. The action is trigger-agnostic; this is a recommendation for the required-check wiring.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

First, tamper resistance: the check will be required, so a PR must not be able to alter its own gate. With pull_request_target the workflow and the action (pinned to the change-management-check/v1 tag) come from the base branch; with pull_request the workflow comes from the PR head, so a PR could rename the job or edit the workflow to pass.

This is understandable. We typically use pull_request regardless - but make sure that the CODEOWNERS is properly set and therefore gates unwanted merges that bypass a workflow.

Second, fork PRs: with pull_request a fork PR's workflow waits for maintainer approval, and the required check shows Expected until then; pull_request_target runs without that step. The usual pull_request_target risk does not apply here: no checkout of PR code, no secrets, the only permission is pull-requests: read (used by the path filter), and the action itself reads only the event payload. The action is trigger-agnostic; this is a recommendation for the required-check wiring.

Is this expected to run against PR from forks?

@tvc-jeffwelling tvc-jeffwelling Oct 21, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not expected. All target repos are private, and the last 300 PRs in each (900 total) include zero fork PRs. If one appeared, the workflow would wait for maintainer approval before running, and the required check would sit Expected until then.

On CODEOWNERS: agreed, and the catch-all rules already cover the workflow path in each target repo. The wiring step will confirm the code-owner review requirement is actually enforced; the enforcement audit found gaps in the current rulesets, and closing them is part of this rollout.

- check.js: drop the files API, glob engine, and exemption inputs.
- check.js: parse CRLF bodies; fail when the sections input is empty.
- check.js: blank comment spans in place instead of deleting them.
- README.md: usage example uses dorny/paths-filter with a conditional
  step; document the required-check skip rules.
- action.yml: remove the docs-paths, dev-paths, and head-prefixes inputs.
@tvc-jeffwelling
tvc-jeffwelling enabled auto-merge (squash) October 21, 2026 21:57
@tvc-jeffwelling
tvc-jeffwelling merged commit 0b2c584 into main Oct 21, 2026
20 checks passed
@tvc-jeffwelling
tvc-jeffwelling deleted the feat/IP-4105-change-management-check branch October 21, 2026 21:58
@gati-app gati-app Bot mentioned this pull request Oct 21, 2026
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.

3 participants