Skip to content

PDP-1182: Add pull_request_target trigger to copyright-check.yml for org ruleset support#43

Merged
GAdityaVarma merged 9 commits intomainfrom
feat/PDP-1182-copyright-check-org-ruleset-support
Apr 9, 2026
Merged

PDP-1182: Add pull_request_target trigger to copyright-check.yml for org ruleset support#43
GAdityaVarma merged 9 commits intomainfrom
feat/PDP-1182-copyright-check-org-ruleset-support

Conversation

@SameeraPriyathamTadikonda
Copy link
Copy Markdown
Contributor

@SameeraPriyathamTadikonda SameeraPriyathamTadikonda commented Apr 8, 2026

Summary

Adds pull_request_target trigger to copyright-check.yml so it can be invoked directly via org-level repository rulesets, eliminating the need for a per-repo pr-workflow.yaml caller file.

What changed

Change Reason
Added pull_request_target trigger (types: opened, edited, synchronize, reopened) Enables org ruleset to fire this workflow directly — no per-repo caller file needed
Retained workflow_call trigger Backward compatibility with existing per-repo callers (~30 repos)
pull-requests: writepull-requests: read Least privilege — PR comments use github.rest.issues.* APIs, not the Pull Requests API
Checkout refs/pull/N/head (not head.sha) This named ref is always available in the base repo for both fork and non-fork PRs; head.sha can fail for fork PRs if the SHA is not yet in the base repo object store
Switched from git diff to gh api .../pulls/.../files for changed files Does not require fetching PR branch commits into base repo; works reliably for forks
File list passed via --files-from-stdin Prevents argument injection via filenames starting with -- or containing spaces
COPYRIGHT_CHECK_COMMIT_SHA derived from git -C target-repo rev-parse HEAD Matches what was actually checked out, not the event payload SHA
PR comment step skipped for pull_request_target Org required workflow token is read-only for triggering repo; createComment would 403. Job Summary used instead
All ${{ }} expressions moved to env: blocks Script injection prevention (SECCMP-1797): attacker-controlled context values (PR title, head SHA, etc.) are passed as env vars, never interpolated directly into run: blocks
All actions pinned to immutable commit SHAs Supply chain hardening (SECCMP-1797): actions/checkout@34e114876b..., actions/setup-python@7f4fc3e22c..., actions/github-script@f28e40c7f3...

PwnRequest Safety (SECCMP-1797)

Prerequisite Present? Notes
pull_request_target trigger ✅ Yes Required for fork PR support via org ruleset
PR code checkout ✅ Yes refs/pull/N/head checked out into runner workspace
Code execution from PR code ❌ No copyrightcheck.py runs from this trusted repo; fork files are only read as text (never executed). Analogous to a virus scanner reading a suspect file. PwnRequest triad broken at step 3.

Why it is safe for fork PRs

Concern Status
Fork code execution ✅ Safe — copyrightcheck.py runs from this trusted repo; only reads fork files as text (never executes them)
Token exposure ✅ Safe — persist-credentials: false on all checkouts
Argument injection via filenames ✅ Fixed — file list passed via stdin (--files-from-stdin), not shell word expansion
Fork .copyrightconfig bypass ✅ Acceptable — worst case is check passes (policy bypass); maintainer reviews diff before merge
${{ }} injection in run: ✅ Fixed — all event payload expressions are in env: vars, never inlined into shell commands

Jira compliance

Requirement Source Status
Remove unnecessary write permissions PDP-1182 / SECCMP-1797 pull-requests: writeread; issues: write scoped to comment step only
Fix script injection via attacker-controlled input SECCMP-1797 ✅ All ${{ }} moved to env: vars
Fork PR support via org ruleset PDP-1182 pull_request_target + refs/pull/N/head
Supply chain hardening SECCMP-1797 ✅ All actions pinned to immutable commit SHAs
Break PwnRequest triad SECCMP-1797 ✅ Triad broken — no code execution from PR files

Test matrix — marklogic/copyrighttest

Tested via org ruleset TestPRworkflows pointing to feat/PDP-1182-copyright-check-org-ruleset-support. All 8 scenarios verified against commit 500c96b on 2026-04-08.

# Scenario Type PR Expected Result
T1 All changed files have valid copyright main-repo #119 ✅ pass ✅ pass
T2 A changed .java file has no copyright header main-repo #118 ❌ fail ❌ fail
T3 File is in filesexcluded list, no copyright header main-repo #120 ✅ pass ✅ pass
T4 Only .md files changed (README) main-repo #116 ✅ pass (no-op) ✅ pass
T5 Fork PR — valid copyright headers fork #121 ✅ pass ✅ pass
T6 Fork PR — missing copyright header fork #123 ❌ fail ❌ fail
T7 Fork PR — fork .copyrightconfig excludes added file fork #122 ✅ pass ✅ pass
T9 PR only deletes files (no files to validate) main-repo #117 ✅ pass (no-op) ✅ pass

T2 and T6 correctly fail with: Copyright headers are missing or invalid — see the Job Summary for details.
T4 and T9 correctly emit: ::notice title=Copyright Check::No files to validate

Next steps

Once merged to main:

  1. Update org ruleset TestPRworkflows to point to @main instead of the feature branch
  2. Configure ruleset for remaining repos in github.com/organizations/marklogic/settings/rules
  3. Remove per-repo pr-workflow.yaml files from the ~30 consumer repos

Enable copyright-check to be used directly via org-level repository
rulesets without requiring a per-repo pr-workflow.yaml caller.

- Adds pull_request_target trigger (opened, edited, synchronize, reopened)
- Retains workflow_call for backward compat with existing per-repo callers
- Safe for fork PRs: copyrightcheck.py (from trusted pr-workflows repo)
  only reads fork files as text — no code execution risk
- Worst case from malicious fork .copyrightconfig is check passes
  (policy bypass only, not security exploit); reviewed by maintainer

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 8, 2026 18:38
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a pull_request_target trigger to the shared copyright validation workflow so it can be enforced directly via org-level repository rulesets, while keeping workflow_call for existing per-repo callers.

Changes:

  • Added pull_request_target trigger (opened/edited/synchronize/reopened) for ruleset compatibility
  • Kept workflow_call for backward compatibility
  • Documented the fork-PR safety rationale in workflow comments

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

Comment thread .github/workflows/copyright-check.yml
Comment thread .github/workflows/copyright-check.yml Outdated
- Fixes SECCMP-1797 regression: git fetch failed with exit code 128
  for private repos because persist-credentials:false removed the token
  after checkout, leaving no credentials for subsequent git fetch
- Use gh api /pulls/{n}/files instead — no git credentials needed,
  works for public, private, and fork PRs equally
- Use IFS= read -r to correctly handle filenames with spaces
- Deleted files naturally filtered by [ -f target-repo/$f ] check

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.


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

Comment thread .github/workflows/copyright-check.yml
- Remove pull-requests: write permission (only issues: write needed for
  issue comment APIs; pull-requests: write was unnecessary scope)
- Use refs/pull/N/head for fork PR checkout (more reliable than SHA
  fetch for pull_request_target; explicit named ref always resolvable)
- Use --files-from-stdin to pass files to copyrightcheck.py (eliminates
  shell word-splitting and argument injection via filenames starting
  with '--')

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.


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

Comment thread .github/workflows/copyright-check.yml
…oint

The explicit permissions block restricts the GITHUB_TOKEN to only listed
scopes. The 'gh api repos/.../pulls/.../files' call uses the Pull Requests
API which requires pull-requests: read. Without it the call can 403 on
private repos.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 3 comments.


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

Comment thread .github/workflows/copyright-check.yml Outdated
Comment thread .github/workflows/copyright-check.yml
Comment thread .github/workflows/copyright-check.yml
When a PR only deletes files, '[ -f target-repo/$f ] && echo $f'
returns exit code 1 (false && skipped-cmd). With bash pipefail this
causes 'Get changed files' to fail before writing skip-validation=true,
making all always() steps run with empty VALIDATION_STATUS.

Using if/then/fi instead exits 0 when condition is false (no else),
so the pipeline succeeds and the empty-file-list path works correctly.

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

Two bugs fixed:

1. set -e: python3 exits 1 causing bash to exit before ec=$? and
   status=failed can be written to GITHUB_OUTPUT. Use &&/|| pattern
   so status is always written before the exit.

2. PR comment 403: org required workflows (pull_request_target via
   org ruleset) receive a read-only token for the triggering repo —
   createComment/updateComment always 403. Skip the comment step for
   pull_request_target and rely on Job Summary instead. workflow_call
   path still posts PR comments (token has write access to calling repo).

Also improves the fallback error message to point to Job Summary.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.


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

… checkout

- Line 5 comment: 'write token' was misleading after the token was
  scoped down to least privilege. Updated to accurately state that
  GITHUB_TOKEN is explicitly scoped in the job permissions block.

- COPYRIGHT_CHECK_COMMIT_SHA: moved from env: block (GitHub context)
  to git -C target-repo rev-parse HEAD in the run: script. This
  guarantees the reported SHA matches what was actually checked out,
  not the event payload SHA which can theoretically diverge.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.


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

Comment thread .github/workflows/copyright-check.yml
…vent paths

GitHub Actions has no per-event conditional permissions within a single job.
Splitting into two jobs (one per event type) would require artifact sharing
for summary.md/validation_output.txt and adds complexity for minimal gain.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@SameeraPriyathamTadikonda SameeraPriyathamTadikonda requested a review from a team April 8, 2026 21:08
SameeraPriyathamTadikonda added a commit that referenced this pull request Apr 8, 2026
copyright-check.yml action pinning belongs in PR #43 only.
Keep each PR to a single workflow file.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.


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

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.


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

Comment thread .github/workflows/copyright-check.yml
Pin actions/checkout@v4, actions/setup-python@v4, and actions/github-script@v7
to immutable commit SHAs to prevent supply chain attacks.

- actions/checkout -> 34e114876b0b11c390a56381ad16ebd13914f8d5
- actions/setup-python -> 7f4fc3e22c37d6ff65e88745f38bd3157c663f7c
- actions/github-script -> f28e40c7f34bde8b3046d885e986cb6290c5673b

Note: reverts accidental regression introduced in prior SHA-pin attempt that
inadvertently reverted pull_request_target trigger, refs/pull/N/head checkout
ref, pull-requests: read permission, and --files-from-stdin argument safety.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.


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

Copy link
Copy Markdown
Collaborator

@GAdityaVarma GAdityaVarma left a comment

Choose a reason for hiding this comment

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

Changes looks good.

@GAdityaVarma GAdityaVarma merged commit 0c7eb0f into main Apr 9, 2026
6 checks passed
@GAdityaVarma GAdityaVarma deleted the feat/PDP-1182-copyright-check-org-ruleset-support branch April 9, 2026 09:31
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