feat: onboard FullSend JIRA integration - #324
Conversation
Adds a scheduled GitHub Actions workflow that polls JIRA for issues matching the ocm-agent-operator component in ROSAENG, excluding security-sensitive issues (Vulnerability, Weakness types and security/cve/embargo labels). Closes openshift#323 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
WalkthroughThe new GitHub Actions workflow polls Jira on a schedule or manual dispatch, records Fullsend results, and dispatches matching stage workflows with issue metadata. ChangesFullsend Jira integration
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant GitHubActions
participant Fullsend
participant Jira
participant GitHubCLI
participant StageWorkflow
GitHubActions->>Fullsend: Run Jira polling command
Fullsend->>Jira: Query issues with credentials and JQL
Jira-->>Fullsend: Return matching issues
Fullsend-->>GitHubActions: Write dispatch records
GitHubActions->>GitHubCLI: Resolve fullsend-stage workflow
GitHubCLI-->>GitHubActions: Return matching workflow
GitHubActions->>GitHubCLI: Dispatch workflow with issue metadata
GitHubCLI->>StageWorkflow: Start stage workflow
🚥 Pre-merge checks | ✅ 15✅ Passed checks (15 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: samanthajayasinghe The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
🤖 Finished Review · ✅ Success · Started 11:09 PM UTC · Completed 11:26 PM UTC |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/fullsend-poll-jira.yaml:
- Line 19: Update the actions/checkout step in the workflow to reference a
reviewed full commit SHA instead of the floating v4 tag, while preserving the
existing checkout configuration.
- Line 19: Update the actions/checkout step in the workflow to set
persist-credentials to false and replace the floating `@v4` reference with the
full commit SHA for the selected checkout release.
- Around line 28-42: Add a pinned SAST/SCA scanner action or reusable security
workflow between the “Poll Jira” and “Dispatch agent workflows” steps. Configure
it to scan the checked-out repository and fail the job when vulnerabilities or
scan errors are detected, while preserving the existing dispatch step only after
a successful scan.
- Around line 73-89: Add a workflow with a `workflow_dispatch` trigger and mark
it using `# fullsend-stage: <stage>` so the discovery loop in the dispatcher can
find it. Define dispatch inputs named `event_type`, `source_repo`, and
`event_payload`, matching the values passed by `gh workflow run`; use the
appropriate stage marker expected by the Jira records.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Central YAML (inherited)
Review profile: CHILL
Plan: Enterprise
Run ID: 7fde4b81-670d-4d6a-9c12-a30dcd8e5681
📒 Files selected for processing (1)
.github/workflows/fullsend-poll-jira.yaml
| group: fullsend-jira-poll | ||
| cancel-in-progress: false | ||
| steps: | ||
| - uses: actions/checkout@v4 |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
file=".github/workflows/fullsend-poll-jira.yaml"
sed -n '1,80p' "$file"
printf '\n--- action references ---\n'
rg -n 'uses:|permissions:|schedule:|workflow_dispatch:|pull_request|issues|contents' "$file"Repository: openshift/ocm-agent-operator
Length of output: 2971
Supply-chain Action Pinning (CWE-829): Inclusion of Functionality from Untrusted Control Sphere
Reachability: External · Exploitability: Moderate
Pin actions/checkout to a full commit SHA.
Replace actions/checkout@v4 with a reviewed full commit SHA.
🧰 Tools
🪛 zizmor (1.29.0)
[warning] 19-19: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/fullsend-poll-jira.yaml at line 19, Update the
actions/checkout step in the workflow to reference a reviewed full commit SHA
instead of the floating v4 tag, while preserving the existing checkout
configuration.
Source: Path instructions
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- workflow files ---'
git ls-files '.github/workflows/fullsend-poll-jira.yaml' '.github/workflows/fullsend.yaml'
printf '%s\n' '--- target workflow ---'
cat -n .github/workflows/fullsend-poll-jira.yaml
printf '%s\n' '--- related Fullsend references ---'
rg -n -C 3 'fullsend|GH_TOKEN|GITHUB_TOKEN|checkout|permissions|pull_request|issue' .github/workflows/fullsend-poll-jira.yaml .fullsend/config.yamlRepository: openshift/ocm-agent-operator
Length of output: 10043
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
p = Path(".github/workflows/fullsend-poll-jira.yaml")
lines = p.read_text().splitlines()
checkout = next(i for i, line in enumerate(lines) if "actions/checkout@" in line)
install = next(i for i, line in enumerate(lines) if "gh release download" in line)
poll = next(i for i, line in enumerate(lines) if "fullsend poll" in line)
actions_write = any(line.strip() == "actions: write" for line in lines)
print({
"checkout_line": checkout + 1,
"download_line": install + 1,
"poll_line": poll + 1,
"checkout_precedes_fullsend": checkout < install < poll,
"actions_write_granted": actions_write,
"explicit_gh_token_steps": [
i + 1 for i, line in enumerate(lines)
if line.strip() == "GH_TOKEN: ${{ github.token }}"
],
})
PY
for url in \
'https://api.github.com/repos/actions/checkout/git/ref/tags/v4.2.2' \
'https://api.github.com/repos/actions/checkout/commits/11bd71901bbe5b1630ceea73d27597364c9af683'
do
echo "--- $url"
curl -fsSL "$url" | jq '{ref: .ref, object: .object, sha: .sha}'
doneRepository: openshift/ocm-agent-operator
Length of output: 597
Sensitive Data Exposure (CWE-522): Insufficiently Protected Credentials
Reachability: External · Exploitability: Moderate
Disable persisted checkout credentials and pin actions/checkout to a full SHA.
actions/checkout stores the GitHub token in local Git configuration by default. The downloaded fullsend binary runs afterward in the same workspace and could read this token if compromised. Set persist-credentials: false and replace @v4 with the full SHA for the selected release.
🧰 Tools
🪛 zizmor (1.29.0)
[warning] 19-19: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/fullsend-poll-jira.yaml at line 19, Update the
actions/checkout step in the workflow to set persist-credentials to false and
replace the floating `@v4` reference with the full commit SHA for the selected
checkout release.
Source: Linters/SAST tools
| - name: Poll Jira | ||
| env: | ||
| JIRA_TOKEN: ${{ secrets.JIRA_TOKEN }} | ||
| JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} | ||
| JIRA_BASE_URL: ${{ vars.JIRA_BASE_URL }} | ||
| run: | | ||
| fullsend poll \ | ||
| --input-driver jira-poll \ | ||
| --jira-url "${JIRA_BASE_URL}" \ | ||
| --jql 'project = ROSAENG AND component = ocm-agent-operator AND issuetype in (Bug, Story, Feature) AND issuetype not in (Vulnerability, Weakness) AND labels not in (security, cve, embargo) AND status not in (Closed, Done, "Won'\''t Do")' \ | ||
| --target-repo "${{ github.repository }}" \ | ||
| --output dispatches.json \ | ||
| --fullsend-dir .fullsend | ||
|
|
||
| - name: Dispatch agent workflows |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- workflow files and relevant references ---'
git ls-files '.github/workflows/fullsend-poll-jira.yaml' '.github/workflows/fullsend.yaml' '.fullsend/config.yaml'
printf '%s\n' '--- fullsend-poll-jira.yaml ---'
cat -n .github/workflows/fullsend-poll-jira.yaml
printf '%s\n' '--- related Fullsend references ---'
rg -n -C 3 'fullsend|dispatch|checkout|scan|sast|sca|semgrep|codeql|dependency|jira-poll' \
.github/workflows/fullsend-poll-jira.yaml .github/workflows/fullsend.yaml .fullsend/config.yamlRepository: openshift/ocm-agent-operator
Length of output: 14345
Security Misconfiguration (CWE-693)
Exploitability: Moderate
Add a pinned SAST/SCA gate before agent dispatch.
This workflow installs an external Fullsend binary and dispatches agent workflows. Add a pinned scanner action or reusable security workflow before Dispatch agent workflows, and fail the job when scanning fails.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/fullsend-poll-jira.yaml around lines 28 - 42, Add a pinned
SAST/SCA scanner action or reusable security workflow between the “Poll Jira”
and “Dispatch agent workflows” steps. Configure it to scan the checked-out
repository and fail the job when vulnerabilities or scan errors are detected,
while preserving the existing dispatch step only after a successful scan.
Source: Path instructions
| for wf in .github/workflows/*.yml .github/workflows/*.yaml; do | ||
| [[ -f "$wf" ]] || continue | ||
| if grep -qxF "# fullsend-stage: ${STAGE}" "$wf"; then | ||
| WORKFLOW_NAME=$(basename "$wf") | ||
| break | ||
| fi | ||
| done | ||
| if [[ -z "$WORKFLOW_NAME" ]]; then | ||
| echo "::warning::No workflow found for stage ${STAGE}, skipping ${RESOURCE_KEY}" | ||
| continue | ||
| fi | ||
|
|
||
| echo "Dispatching ${WORKFLOW_NAME} for ${ISSUE_KEY} (${STAGE})" | ||
| gh workflow run "$WORKFLOW_NAME" \ | ||
| -f event_type="$EVENT_TYPE" \ | ||
| -f source_repo="${{ github.repository }}" \ | ||
| -f event_payload="$EVENT_PAYLOAD" |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
fd -e yml -e yaml .github/workflows -x sh -c '
if rg -q "^# fullsend-stage:" "$1"; then
echo "=== $1 ==="
rg -n -C 8 "^# fullsend-stage:|workflow_dispatch:|event_type:|source_repo:|event_payload:" "$1"
fi
' sh {}Repository: openshift/ocm-agent-operator
Length of output: 540
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '=== Stage-marked workflows ==='
rg -l '^# fullsend-stage:' .github/workflows --glob '*.yml' --glob '*.yaml' |
while IFS= read -r wf; do
printf '\n=== %s ===\n' "$wf"
rg -n -C 12 '^# fullsend-stage:|workflow_dispatch:|^[[:space:]]+(event_type|source_repo|event_payload):' "$wf" || true
done
printf '\n=== Dispatcher context ===\n'
cat -n .github/workflows/fullsend-poll-jira.yaml | sed -n '45,105p'Repository: openshift/ocm-agent-operator
Length of output: 197
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '=== Workflow files ==='
git ls-files '.github/workflows/*' | sort
printf '\n%s\n' '=== Fullsend references ==='
rg -n -i -C 4 'fullsend|stage:|workflow_dispatch|event_type|source_repo|event_payload' .github/workflows || true
printf '\n%s\n' '=== Dispatcher workflow ==='
cat -n .github/workflows/fullsend-poll-jira.yaml | sed -n '1,130p'Repository: openshift/ocm-agent-operator
Length of output: 14365
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '=== Fullsend configuration files ==='
git ls-files | rg '(^|/)(\.fullsend|fullsend)(/|\.|$)' | sort
printf '\n%s\n' '=== Stage and dispatch declarations across tracked files ==='
rg -n -i -C 5 'fullsend-stage|stage:|workflow_dispatch|event_type|source_repo|event_payload|reusable-dispatch' \
$(git ls-files) || true
printf '\n%s\n' '=== Fullsend workflow ==='
cat -n .github/workflows/fullsend.yaml | sed -n '1,125p'Repository: openshift/ocm-agent-operator
Length of output: 11908
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '=== Fullsend configuration ==='
cat -n .fullsend/config.yaml
printf '\n%s\n' '=== Marker and input-contract verifier ==='
python3 - <<'PY'
from pathlib import Path
import re
workflow_dir = Path(".github/workflows")
marker_re = re.compile(r"^# fullsend-stage:\s*(\S+)\s*$")
input_re = {
"event_type": re.compile(r"^\s+event_type\s*:"),
"source_repo": re.compile(r"^\s+source_repo\s*:"),
"event_payload": re.compile(r"^\s+event_payload\s*:"),
}
dispatch_re = re.compile(r"^\s+workflow_dispatch\s*:")
marked = []
for path in sorted(workflow_dir.glob("*")):
if path.suffix not in {".yml", ".yaml"}:
continue
lines = path.read_text().splitlines()
stages = [m.group(1) for line in lines if (m := marker_re.match(line))]
if stages:
marked.append((path, stages, lines))
print(f"marked_workflow_count={len(marked)}")
if not marked:
print("result=no workflow can match the dispatcher marker")
for path, stages, lines in marked:
present = {
name: any(pattern.search(line) for line in lines)
for name, pattern in input_re.items()
}
print(path, "stages=" + ",".join(stages),
"workflow_dispatch=" + str(any(dispatch_re.search(line) for line in lines)),
"inputs=" + ",".join(f"{k}:{v}" for k, v in present.items()))
PYRepository: openshift/ocm-agent-operator
Length of output: 1005
Add a stage-marked dispatch workflow.
No workflow contains # fullsend-stage:, so every Jira record follows the warning path and is skipped. Add a marked workflow with workflow_dispatch inputs for event_type, source_repo, and event_payload, or remove this dispatcher.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/fullsend-poll-jira.yaml around lines 73 - 89, Add a
workflow with a `workflow_dispatch` trigger and mark it using `# fullsend-stage:
<stage>` so the discovery loop in the dispatcher can find it. Define dispatch
inputs named `event_type`, `source_repo`, and `event_payload`, matching the
values passed by `gh workflow run`; use the appropriate stage marker expected by
the Jira records.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #324 +/- ##
=======================================
Coverage 65.03% 65.03%
=======================================
Files 23 23
Lines 1570 1570
=======================================
Hits 1021 1021
Misses 471 471
Partials 78 78 🚀 New features to boost your workflow:
|
|
@samanthajayasinghe: The following test failed, say
Full PR test history. Your PR dashboard. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here. |
ReviewFindingsHigh
Medium
Low
Labels: PR adds new feature: JIRA polling integration workflow Next steps:
|
| WORKFLOW_NAME="" | ||
| for wf in .github/workflows/*.yml .github/workflows/*.yaml; do | ||
| [[ -f "$wf" ]] || continue | ||
| if grep -qxF "# fullsend-stage: ${STAGE}" "$wf"; then |
There was a problem hiding this comment.
[high] logic-error
The dispatch loop searches all workflow files for a # fullsend-stage: ${STAGE} comment using grep -qxF, but no workflow file in this repository contains any fullsend-stage comment. Every dispatch record will hit the No workflow found branch and be skipped. The entire dispatch mechanism is non-functional — the workflow will poll Jira every 5 minutes but never dispatch anything.
Suggested fix: Either add # fullsend-stage: comments to the target workflow files, or document this dependency and guard the workflow until consumers exist.
| echo "Dispatching ${WORKFLOW_NAME} for ${ISSUE_KEY} (${STAGE})" | ||
| gh workflow run "$WORKFLOW_NAME" \ | ||
| -f event_type="$EVENT_TYPE" \ | ||
| -f source_repo="${{ github.repository }}" \ |
There was a problem hiding this comment.
[medium] consumer-completeness
Even if fullsend-stage comments were added, gh workflow run passes -f event_type, -f source_repo, and -f event_payload. No workflow in this repository defines a workflow_dispatch trigger with these input parameters.
Suggested fix: Ensure target workflows define workflow_dispatch with inputs for event_type, source_repo, and event_payload.
| GH_TOKEN: ${{ github.token }} | ||
| run: | | ||
| gh release download --repo fullsend-ai/fullsend -p 'fullsend_*_linux_amd64.tar.gz' -O - | tar xz | ||
| sudo mv fullsend /usr/local/bin/ |
There was a problem hiding this comment.
[medium] supply-chain
The workflow downloads and executes a binary from fullsend-ai/fullsend releases without version pinning or checksum verification. A compromise of the upstream repo could deliver a malicious binary with access to JIRA_TOKEN, JIRA_USER_EMAIL, and github.token. This contradicts the repos convention of SHA-pinning external dependencies.
Suggested fix: Pin the download to a specific release tag (gh release download v0.32.0 --repo fullsend-ai/fullsend) and verify the checksum.
| done | ||
| if [[ -z "$WORKFLOW_NAME" ]]; then | ||
| echo "::warning::No workflow found for stage ${STAGE}, skipping ${RESOURCE_KEY}" | ||
| continue |
There was a problem hiding this comment.
[medium] workflow-command-injection
The ::warning:: command (line 82) and echo (line 87) interpolate unsanitized Jira-derived variables (STAGE, RESOURCE_KEY/ISSUE_KEY). If Jira metadata contains %0A or :: sequences, an attacker could inject GitHub Actions workflow commands.
Suggested fix: Sanitize Jira-derived variables before interpolating — strip newlines and replace :: sequences, or use printf instead of workflow commands.
| group: fullsend-jira-poll | ||
| cancel-in-progress: false | ||
| steps: | ||
| - uses: actions/checkout@v4 |
There was a problem hiding this comment.
[medium] version-pinning
The existing fullsend.yaml pins external actions to full commit SHAs. This file uses actions/checkout@v4 (mutable tag), inconsistent with the repos pinning convention.
Suggested fix: Pin to full SHA: actions/checkout@11bd719 # v4.2.2.
| ISSUE_ID=$(echo "$record" | jq -r '.iid // 0') | ||
|
|
||
| ISSUE_KEY="${RESOURCE_KEY#issue-}" | ||
| ISSUE_URL="${JIRA_BASE_URL}/browse/${ISSUE_KEY}" |
There was a problem hiding this comment.
[low] error-handling
ISSUE_ID is set via jq -r .iid // 0. If .iid is present but non-numeric, --argjson number will fail due to set -e. While Jira IDs are inherently numeric, defensive coding would use jq tonumber.
Suggested fix: Use jq -r (.iid // 0) | tonumber to ensure numeric.
| @@ -0,0 +1,94 @@ | |||
| name: fullsend Jira poll | |||
There was a problem hiding this comment.
[low] document-structure
Existing fullsend.yaml uses --- YAML document start marker and places permissions before on. This file omits the marker and reverses top-level key order.
Suggested fix: Add --- and reorder to match existing convention.
|
|
||
| EVENT_PAYLOAD=$(jq -nc \ | ||
| --argjson number "$ISSUE_ID" \ | ||
| --arg url "$ISSUE_URL" \ |
There was a problem hiding this comment.
[low] error-handling
If vars.JIRA_BASE_URL is not configured, ISSUE_URL becomes /browse/${ISSUE_KEY} (missing scheme/host), producing an invalid URL in the event payload.
Suggested fix: Add validation at start of dispatch step for JIRA_BASE_URL.
| @@ -0,0 +1,94 @@ | |||
| name: fullsend Jira poll | |||
There was a problem hiding this comment.
[low] header-comment
Existing fullsend.yaml has a header comment block explaining purpose, security model, and routing logic. This file has no comments.
| @@ -0,0 +1,94 @@ | |||
| name: fullsend Jira poll | |||
There was a problem hiding this comment.
[low] naming-convention
Existing workflow name is fullsend (lowercase, no spaces). New workflow is fullsend Jira poll with mixed case. Consider consistent naming.
Summary
.github/workflows/fullsend-poll-jira.yaml) that polls JIRA every 5 minutes forocm-agent-operatorissuesPrerequisites
The following secrets/variables must be configured in the repo (Settings > Secrets and variables > Actions):
JIRA_TOKENJIRA_USER_EMAILJIRA_BASE_URLhttps://issues.redhat.com)Test plan
workflow_dispatchand confirm it runs without errorsCloses #323
🤖 Generated with Claude Code
Summary by CodeRabbit