Skip to content

feat: onboard FullSend JIRA integration - #324

Open
samanthajayasinghe wants to merge 1 commit into
openshift:masterfrom
samanthajayasinghe:fix/323-jira-integration
Open

feat: onboard FullSend JIRA integration#324
samanthajayasinghe wants to merge 1 commit into
openshift:masterfrom
samanthajayasinghe:fix/323-jira-integration

Conversation

@samanthajayasinghe

@samanthajayasinghe samanthajayasinghe commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds scheduled GitHub Actions workflow (.github/workflows/fullsend-poll-jira.yaml) that polls JIRA every 5 minutes for ocm-agent-operator issues
  • Uses the JQL query from ROSAENG-62420: Onboard FullSend JIRA Integration #323 to filter for Bug/Story/Feature types in ROSAENG project
  • Excludes security-sensitive issues (Vulnerability/Weakness types, security/cve/embargo labels)

Prerequisites

The following secrets/variables must be configured in the repo (Settings > Secrets and variables > Actions):

Name Type Value
JIRA_TOKEN Secret Jira API token
JIRA_USER_EMAIL Secret Email associated with the token
JIRA_BASE_URL Variable Jira instance URL (e.g. https://issues.redhat.com)

Test plan

  • Verify JIRA secrets/variables are configured in repo settings
  • Trigger workflow manually via workflow_dispatch and confirm it runs without errors
  • Verify security-sensitive issues are excluded from polling results

Closes #323

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added automated Jira polling every five minutes, with support for manual runs.
    • Added filtering and stage-based workflow dispatch using Jira issue information.
    • Added safeguards to skip empty results or unavailable stages.
    • Added dispatch tracking and serialized execution to prevent overlapping runs.

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>
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Walkthrough

The new GitHub Actions workflow polls Jira on a schedule or manual dispatch, records Fullsend results, and dispatches matching stage workflows with issue metadata.

Changes

Fullsend Jira integration

Layer / File(s) Summary
Workflow triggers and execution setup
.github/workflows/fullsend-poll-jira.yaml
The workflow runs every five minutes or through manual dispatch. It sets read and actions permissions, uses Ubuntu, and serializes poll jobs without cancellation.
Jira polling and dispatch record creation
.github/workflows/fullsend-poll-jira.yaml
The workflow checks out the repository, installs Fullsend from its GitHub release, polls Jira with configured credentials and the required JQL filter, and writes dispatches.json and .fullsend.
Stage workflow resolution and dispatch
.github/workflows/fullsend-poll-jira.yaml
The workflow exits when no records exist, extracts issue data, builds Jira URLs and payloads, resolves fullsend-stage workflows, skips missing stages, dispatches matching workflows through GitHub CLI, and reports the dispatch count.

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
Loading
🚥 Pre-merge checks | ✅ 15
✅ Passed checks (15 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding FullSend JIRA integration.
Linked Issues check ✅ Passed The workflow configures FullSend JIRA polling with the required repository, issue, label, and status filters from issue #323.
Out of Scope Changes check ✅ Passed The changes are limited to the FullSend JIRA polling workflow described in issue #323.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Stable And Deterministic Test Names ✅ Passed The pull request changes only one YAML workflow file; the commit adds no Ginkgo It, Describe, Context, or When test titles.
Test Structure And Quality ✅ Passed The pull request changes only one GitHub Actions workflow and adds no Ginkgo test code, so this test-structure check is not applicable.
Microshift Test Compatibility ✅ Passed The patch adds only a GitHub Actions workflow; it adds no Ginkgo e2e tests and references no MicroShift-incompatible APIs or features.
Single Node Openshift (Sno) Test Compatibility ✅ Passed The PR adds only a Jira polling GitHub Actions workflow; it adds no Ginkgo tests or multi-node/HA cluster assumptions.
Topology-Aware Scheduling Compatibility ✅ Passed The change only adds a GitHub Actions polling workflow; it contains no deployment, controller, pod scheduling, affinity, topology, node, replica, or PDB constraints.
Ote Binary Stdout Contract ✅ Passed The PR changes only a GitHub Actions YAML workflow; it adds no OTE binary, suite setup, or process-level stdout write.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed The pull request adds only a GitHub Actions workflow and no new Ginkgo e2e tests, so this IPv6 and disconnected-network test check is not applicable.
No-Weak-Crypto ✅ Passed The added workflow only passes Jira/GitHub tokens to Fullsend and gh; it contains no MD5, SHA1, DES, RC4, Blowfish, ECB, custom crypto, or secret comparisons.
Container-Privileges ✅ Passed The PR changes only a GitHub Actions workflow; it contains no privileged, hostPID, hostNetwork, hostIPC, SYS_ADMIN, or allowPrivilegeEscalation settings.
No-Sensitive-Data-In-Logs ✅ Passed The workflow does not echo Jira credentials, payloads, or the Jira URL; its logs contain only workflow, stage, and issue-key metadata.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@openshift-ci
openshift-ci Bot requested review from TheUndeadKing and ravitri August 5, 2026 23:08
@openshift-ci

openshift-ci Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: samanthajayasinghe
Once this PR has been reviewed and has the lgtm label, please assign bergmannf for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@fullsend-ai-review

fullsend-ai-review Bot commented Aug 5, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 11:09 PM UTC · Completed 11:26 PM UTC
Commit: c9dd50d · View workflow run →

@coderabbitai coderabbitai Bot 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.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 7f9e641 and c9dd50d.

📒 Files selected for processing (1)
  • .github/workflows/fullsend-poll-jira.yaml

group: fullsend-jira-poll
cancel-in-progress: false
steps:
- uses: actions/checkout@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 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.yaml

Repository: 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}'
done

Repository: 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

Comment on lines +28 to +42
- 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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 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.yaml

Repository: 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

Comment on lines +73 to +89
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"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ 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()))
PY

Repository: 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-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 65.03%. Comparing base (7f9e641) to head (c9dd50d).

Additional details and impacted files

Impacted file tree graph

@@           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:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@openshift-ci

openshift-ci Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

@samanthajayasinghe: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/validate c9dd50d link true /test validate

Full PR test history. Your PR dashboard.

Details

Instructions 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.

@fullsend-ai-review

Copy link
Copy Markdown

Review

Findings

High

  • [logic-error] .github/workflows/fullsend-poll-jira.yaml:75 — 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.
    Remediation: Either add # fullsend-stage: <stage-name> comments to the target workflow files that should receive dispatches, or if target workflows will be added in a follow-up PR, document this dependency and consider guarding the workflow until consumers exist.

Medium

  • [consumer-completeness] .github/workflows/fullsend-poll-jira.yaml:88 — 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. The existing fullsend.yaml triggers on issues, issue_comment, pull_request_target, and pull_request_review — not workflow_dispatch.
    Remediation: Ensure target workflows define workflow_dispatch with inputs for event_type, source_repo, and event_payload.

  • [supply-chain] .github/workflows/fullsend-poll-jira.yaml:26 — The workflow downloads and executes a binary from fullsend-ai/fullsend releases using a glob pattern 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 repo's convention — fullsend.yaml pins its reusable workflow to a specific SHA (@3cfa255...).
    Remediation: Pin the download to a specific release tag (gh release download v0.32.0 --repo fullsend-ai/fullsend ...) and verify the binary's checksum.

  • [workflow-command-injection] .github/workflows/fullsend-poll-jira.yaml:82 — 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.
    Remediation: Sanitize Jira-derived variables before interpolating — strip newlines and replace :: sequences, or use printf '%s\n' instead of workflow commands.

  • [version-pinning] .github/workflows/fullsend-poll-jira.yaml:19 — The existing fullsend.yaml pins external actions to full commit SHAs. This file uses actions/checkout@v4 (mutable tag), inconsistent with the repo's pinning convention.
    Remediation: Pin to full SHA, e.g., actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2.

  • [protected-path] .github/workflows/fullsend-poll-jira.yaml — This PR modifies files under the .github/ protected path. The PR links to issue ROSAENG-62420: Onboard FullSend JIRA Integration #323 and explains the rationale. Human approval is always required for protected-path changes, regardless of context.

Low

  • [error-handling] .github/workflows/fullsend-poll-jira.yaml:65ISSUE_ID is set via jq -r '.iid // 0'. If .iid is present but non-numeric, --argjson number "$ISSUE_ID" will fail. Defensive coding: use jq -r '(.iid // 0) | tonumber'.

  • [document-structure] .github/workflows/fullsend-poll-jira.yaml:1 — Existing fullsend.yaml uses --- YAML document start marker and places permissions before on. This file omits the marker and reverses key order.

  • [error-handling] .github/workflows/fullsend-poll-jira.yaml:69 — 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.

  • [header-comment] .github/workflows/fullsend-poll-jira.yaml:1 — Existing fullsend.yaml has a header comment block explaining purpose, security model, and routing logic. This file has no comments.

  • [naming-convention] .github/workflows/fullsend-poll-jira.yaml:1 — Existing workflow name is fullsend (lowercase). New workflow is fullsend Jira poll with mixed case. Consider consistent naming.

  • [stale-doc] CLAUDE.md — CI described as exclusively Tekton-based but does not mention FullSend GitHub Actions workflows.

  • [stale-doc] .claude/agents/ci-agent.md — CI agent documentation only lists Tekton components, not GitHub Actions workflows.


Labels: PR adds new feature: JIRA polling integration workflow


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR

@fullsend-ai-review fullsend-ai-review Bot 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.

See the review comment for full details.

WORKFLOW_NAME=""
for wf in .github/workflows/*.yml .github/workflows/*.yaml; do
[[ -f "$wf" ]] || continue
if grep -qxF "# fullsend-stage: ${STAGE}" "$wf"; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[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 }}" \

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[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/

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[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}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[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" \

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] naming-convention

Existing workflow name is fullsend (lowercase, no spaces). New workflow is fullsend Jira poll with mixed case. Consider consistent naming.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ROSAENG-62420: Onboard FullSend JIRA Integration

2 participants