Skip to content

Commit 1952b3c

Browse files
Merge pull request #42 from marklogic/fix/SECCMP-1797-pwn-request-injection
PDP-1182 SECCMP-1797: Fix PwnRequest shell injection in jira-id-check.yml
2 parents d0f01c6 + 9326a7c commit 1952b3c

3 files changed

Lines changed: 61 additions & 52 deletions

File tree

.github/workflows/copyright-check.yml

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,27 @@ jobs:
1818
with:
1919
ref: ${{ github.event.pull_request.head.sha }}
2020
path: target-repo
21+
persist-credentials: false
2122

2223
- name: Checkout pr-workflows repo
2324
uses: actions/checkout@v4
2425
with:
2526
repository: ${{ github.repository_owner }}/pr-workflows
2627
ref: main
2728
path: pr-workflows
29+
persist-credentials: false
2830

2931
- name: Setup config
3032
id: setup-config
33+
env:
34+
BASE_REF: ${{ github.event.pull_request.base.ref }}
35+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36+
GH_REPO: ${{ github.repository }}
3137
run: |
3238
cfg="target-repo/.copyrightconfig"
3339
if [ ! -f "$cfg" ]; then
34-
git clone --depth 1 --branch ${{ github.event.pull_request.base.ref }} \
35-
https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git base-repo
40+
git clone --depth 1 --branch "$BASE_REF" \
41+
https://x-access-token:${GH_TOKEN}@github.com/${GH_REPO}.git base-repo
3642
[ -f base-repo/.copyrightconfig ] && cfg="base-repo/.copyrightconfig"
3743
fi
3844
[ -f "$cfg" ] || { echo "missing config"; exit 1; }
@@ -47,12 +53,14 @@ jobs:
4753

4854
- name: Get changed files
4955
id: changed-files
56+
env:
57+
BASE_SHA: ${{ github.event.pull_request.base.sha }}
58+
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
59+
BASE_REF: ${{ github.event.pull_request.base.ref }}
5060
run: |
5161
cd target-repo
52-
base_sha="${{ github.event.pull_request.base.sha }}"
53-
head_sha="${{ github.event.pull_request.head.sha }}"
54-
git fetch origin ${{ github.event.pull_request.base.ref }}
55-
git diff --name-only --diff-filter=AMR "$base_sha" "$head_sha" | while read f; do [ -f "$f" ] && echo "$f"; done > ../files_to_check.txt
62+
git fetch origin "$BASE_REF"
63+
git diff --name-only --diff-filter=AMR "$BASE_SHA" "$HEAD_SHA" | while read f; do [ -f "$f" ] && echo "$f"; done > ../files_to_check.txt
5664
count=$(wc -l < ../files_to_check.txt | tr -d ' ')
5765
if [ "$count" -eq 0 ]; then echo "skip-validation=true" >> $GITHUB_OUTPUT; else echo "skip-validation=false" >> $GITHUB_OUTPUT; fi
5866
echo "files-count=$count" >> $GITHUB_OUTPUT
@@ -63,9 +71,10 @@ jobs:
6371
continue-on-error: true
6472
env:
6573
COPYRIGHT_CHECK_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
74+
CONFIG_FILE: ${{ steps.setup-config.outputs.config-file }}
6675
run: |
6776
script="pr-workflows/scripts/copyrightcheck.py"
68-
cfg="${{ steps.setup-config.outputs.config-file }}"
77+
cfg="$CONFIG_FILE"
6978
[ -f "$script" ] || { echo "script missing"; exit 1; }
7079
chmod +x "$script"
7180
files=$(tr '\n' ' ' < files_to_check.txt)
@@ -123,8 +132,9 @@ jobs:
123132
if: always() && steps.changed-files.outputs.skip-validation != 'true'
124133
env:
125134
COMMENT_ACTION: ${{ steps.pr-comment.outputs.comment_action }}
135+
VALIDATION_STATUS: ${{ steps.validate.outputs.status }}
126136
run: |
127-
if [ "${{ steps.validate.outputs.status }}" != "success" ]; then
137+
if [ "$VALIDATION_STATUS" != "success" ]; then
128138
if [ "$COMMENT_ACTION" = "updated" ] || [ "$COMMENT_ACTION" = "created" ]; then
129139
echo "::error title=Copyright Validation Failed::See the $COMMENT_ACTION PR comment for detailed results.";
130140
else
@@ -135,4 +145,4 @@ jobs:
135145
136146
- name: No-op summary
137147
if: steps.changed-files.outputs.skip-validation == 'true'
138-
run: echo "::notice title=Copyright Check::No files to validate"
148+
run: echo "::notice title=Copyright Check::No files to validate"

.github/workflows/jira-id-check.yml

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,6 @@ on:
1616
required: false
1717
type: string
1818
description: 'The PR title to check (for pull_request_target support)'
19-
regex-pattern:
20-
required: false
21-
type: string
22-
description: 'Custom regex pattern to match JIRA IDs (defaults to "[A-Z]+-[0-9]+")'
23-
default: '[A-Z]+-[0-9]+'
24-
fail-if-no-jira-id:
25-
required: false
26-
type: string
27-
description: 'Whether to fail the check if no JIRA ID is found'
28-
default: 'true'
2919
allow-wip:
3020
required: false
3121
type: string
@@ -40,68 +30,69 @@ on:
4030
jobs:
4131
check-jira-id:
4232
runs-on: ubuntu-latest
33+
permissions:
34+
pull-requests: read
4335
steps:
4436
- name: 🏷️ Validate JIRA ticket ID in PR title
4537
shell: bash
4638
env:
4739
GH_TOKEN: ${{ github.token }}
40+
INPUT_PR_TITLE: ${{ inputs.pr-title }}
41+
EVENT_PR_TITLE: ${{ github.event.pull_request.title }}
42+
PR_NUMBER: ${{ github.event.pull_request.number }}
43+
GH_REPO: ${{ github.repository }}
44+
INPUT_ALLOW_WIP: ${{ inputs.allow-wip }}
45+
INPUT_CASE_SENSITIVE: ${{ inputs.case-sensitive }}
4846
run: |
4947
# Get PR title from context or input parameter (for pull_request_target support)
50-
if [[ -n "${{ inputs.pr-title }}" ]]; then
51-
PR_TITLE="${{ inputs.pr-title }}"
48+
if [[ -n "$INPUT_PR_TITLE" ]]; then
49+
PR_TITLE="$INPUT_PR_TITLE"
5250
echo "Using PR title from input parameter"
5351
else
54-
PR_TITLE="${{ github.event.pull_request.title }}"
52+
PR_TITLE="$EVENT_PR_TITLE"
5553
echo "Using PR title from GitHub event context"
5654
fi
57-
55+
5856
# Fetch the current PR title from the API to handle re-runs correctly.
5957
# When a workflow is re-run (either directly or via a reusable workflow caller),
6058
# the event payload contains the title from the original trigger, not the current
6159
# state. If the user edited the title (e.g., to add a JIRA ID), we need to detect
6260
# that and use the updated title instead.
63-
PR_NUMBER="${{ github.event.pull_request.number }}"
6461
if [[ -n "$PR_NUMBER" ]]; then
6562
LIVE_TITLE=$(gh pr view "$PR_NUMBER" \
66-
--repo "${{ github.repository }}" \
63+
--repo "$GH_REPO" \
6764
--json title --jq '.title' 2>/dev/null || true)
68-
65+
6966
if [[ -n "$LIVE_TITLE" && "$LIVE_TITLE" != "$PR_TITLE" ]]; then
70-
echo "⚠️ PR title was updated since workflow was triggered"
71-
echo " Event title: $PR_TITLE"
72-
echo " Current title: $LIVE_TITLE"
67+
echo "PR title was updated since workflow was triggered"
68+
echo " Event title: $PR_TITLE"
69+
echo " Current title: $LIVE_TITLE"
7370
PR_TITLE="$LIVE_TITLE"
7471
fi
7572
fi
7673
echo "PR Title: $PR_TITLE"
77-
78-
# Set up inputs as environment variables
79-
# JIRA project keys are defined at the organization level
80-
JIRA_PROJECT_KEYS="${{ env.ORGANIZATION_JIRA_PROJECT_KEYS }}"
81-
REGEX_PATTERN="${{ inputs.regex-pattern }}"
82-
FAIL_IF_NO_JIRA_ID="${{ inputs.fail-if-no-jira-id }}"
83-
ALLOW_WIP="${{ inputs.allow-wip }}"
84-
CASE_SENSITIVE="${{ inputs.case-sensitive }}"
85-
74+
75+
JIRA_PROJECT_KEYS="$ORGANIZATION_JIRA_PROJECT_KEYS"
76+
ALLOW_WIP="$INPUT_ALLOW_WIP"
77+
CASE_SENSITIVE="$INPUT_CASE_SENSITIVE"
78+
8679
echo "Using organization-wide JIRA project keys: $JIRA_PROJECT_KEYS"
87-
echo "Using regex pattern: $REGEX_PATTERN"
88-
echo "Fail if no JIRA ID: $FAIL_IF_NO_JIRA_ID"
8980
echo "Allow WIP PRs: $ALLOW_WIP"
9081
echo "Case sensitive: $CASE_SENSITIVE"
91-
82+
9283
# Handle WIP PRs
9384
if [[ "$ALLOW_WIP" == "true" && "${PR_TITLE,,}" =~ ^wip: ]]; then
9485
echo "This is a WIP PR. Skipping JIRA ID check."
9586
exit 0
9687
fi
97-
88+
9889
# Convert comma-separated project keys to array
9990
IFS=',' read -ra PROJECT_KEYS <<< "$JIRA_PROJECT_KEYS"
10091
echo "Valid project keys: ${PROJECT_KEYS[*]}"
101-
92+
10293
# Directly check for valid JIRA IDs in the PR title
10394
VALID_ID_FOUND=false
104-
95+
10596
for VALID_KEY in "${PROJECT_KEYS[@]}"; do
10697
# Create a pattern specifically for this project key
10798
if [[ "$CASE_SENSITIVE" == "true" ]]; then
@@ -122,7 +113,7 @@ jobs:
122113
fi
123114
fi
124115
done
125-
116+
126117
if [[ "$VALID_ID_FOUND" != "true" ]]; then
127118
echo "ERROR: No JIRA ID found in PR title: \"$PR_TITLE\". Valid project keys are: $JIRA_PROJECT_KEYS"
128119
echo "::error::No JIRA ID found in PR title: \"$PR_TITLE\". Valid project keys are: $JIRA_PROJECT_KEYS"

.github/workflows/trufflehog-scan.yml

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ jobs:
4040
uses: actions/checkout@v4
4141
with:
4242
fetch-depth: 0
43+
persist-credentials: false
4344

4445
- name: Fetch PR head commits
4546
if: github.event_name != 'workflow_dispatch'
@@ -50,6 +51,8 @@ jobs:
5051
5152
- name: Setup exclude config
5253
id: config
54+
env:
55+
TRUFFLEHOG_EXCLUDES: ${{ vars.TRUFFLEHOG_EXCLUDES }}
5356
run: |
5457
# Always include default exclusions
5558
echo "Adding default exclusions"
@@ -58,10 +61,10 @@ jobs:
5861
EOF
5962
6063
# Append repo/org-level custom exclusions if defined
61-
if [ -n "${{ vars.TRUFFLEHOG_EXCLUDES }}" ]; then
64+
if [ -n "$TRUFFLEHOG_EXCLUDES" ]; then
6265
echo "Adding repo/org-level TRUFFLEHOG_EXCLUDES patterns"
6366
# Support both comma-separated and newline-separated patterns
64-
echo "${{ vars.TRUFFLEHOG_EXCLUDES }}" | tr ',' '\n' | sed '/^$/d' >> .trufflehog-ignore
67+
echo "$TRUFFLEHOG_EXCLUDES" | tr ',' '\n' | sed '/^$/d' >> .trufflehog-ignore
6568
fi
6669
6770
echo "Exclusion patterns:"
@@ -70,7 +73,8 @@ jobs:
7073
7174
- name: TruffleHog Scan
7275
id: trufflehog
73-
uses: trufflesecurity/trufflehog@main
76+
# Pinned to v3.94.2 commit SHA to prevent supply chain attacks via mutable tag
77+
uses: trufflesecurity/trufflehog@6bd2d14f7a4bc1e569fa3550efa7ec632a4fa67b # v3.94.2
7478
continue-on-error: true
7579
with:
7680
base: ${{ github.event.pull_request.base.sha }}
@@ -107,8 +111,9 @@ jobs:
107111
echo "$CHANGED_FILES"
108112
109113
# Scan only the changed files in their current state using filesystem scanner
114+
# Pinned to v3.94.2 to match the action version above
110115
SCAN_OUTPUT=$(docker run --rm -v "$(pwd)":/tmp -w /tmp \
111-
ghcr.io/trufflesecurity/trufflehog:latest \
116+
ghcr.io/trufflesecurity/trufflehog:3.94.2 \
112117
filesystem /tmp/ \
113118
--json \
114119
${{ steps.config.outputs.exclude_args }} \
@@ -154,9 +159,12 @@ jobs:
154159
- name: Process scan results
155160
id: process
156161
if: github.event_name != 'workflow_dispatch'
162+
env:
163+
VERIFIED_COUNT: ${{ steps.parse.outputs.verified_count }}
164+
UNVERIFIED_COUNT: ${{ steps.parse.outputs.unverified_count }}
157165
run: |
158-
VERIFIED=${{ steps.parse.outputs.verified_count || 0 }}
159-
UNVERIFIED=${{ steps.parse.outputs.unverified_count || 0 }}
166+
VERIFIED=${VERIFIED_COUNT:-0}
167+
UNVERIFIED=${UNVERIFIED_COUNT:-0}
160168
161169
if [ "$VERIFIED" -gt 0 ]; then
162170
# Verified secrets found - must fail
@@ -266,7 +274,7 @@ jobs:
266274
267275
### Understanding Results
268276
| Type | Meaning | Action Required |
269-
|------|---------|-----------------|
277+
|------|---------|--------------------|
270278
| **Verified** | Confirmed active credential | **Must remove & rotate** - PR blocked |
271279
| **Unverified** | Potential secret pattern | Review recommended - PR can proceed |
272280

0 commit comments

Comments
 (0)