feat: add edge-scrum Jira config-as-code with CI automation#14
feat: add edge-scrum Jira config-as-code with CI automation#14jeff-roche wants to merge 1 commit intoopenshift-eng:mainfrom
Conversation
Introduces the edge-scrum tooling directory with: - .jira-config/ — JSON source of truth for boards, filters, projects, components, and labels managed by the OCPEDGE team - .ci/scripts/ — sync scripts that apply config changes to Jira via REST API; credentials sourced from environment variables only - .ci/schemas/ — JSON Schema definitions for all config files - GitHub Actions workflows for PR validation (schema check, README sync enforcement, dry-run preview) and post-merge apply with concurrency control and manual workflow_dispatch trigger Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: jeff-roche The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
WalkthroughThis PR introduces Jira configuration-as-code infrastructure, adding GitHub Actions workflows for validation and synchronization, JSON schema definitions, Bash scripts for CI/CD automation and API integration, Jira metadata configuration files, and supporting documentation. Changes
Sequence DiagramsequenceDiagram
participant GitHub as GitHub
participant Workflow as GitHub Actions
participant Validation as Validation Scripts
participant Orchestration as apply-changes.sh
participant SyncScript as sync-*.sh
participant JiraAPI as Jira REST API
GitHub->>Workflow: Push to main with .jira-config changes
Workflow->>Validation: Run validate-configs.sh
Validation->>Validation: Check schemas & duplicates
Validation-->>Workflow: Validation complete
Workflow->>Orchestration: Run apply-changes.sh
Orchestration->>Orchestration: Detect changed files via git diff
Orchestration->>SyncScript: Execute sync-boards.sh (if boards.json changed)
SyncScript->>SyncScript: Parse config, build payloads
SyncScript->>JiraAPI: PUT /rest/api/2/board/{id}/properties
JiraAPI-->>SyncScript: HTTP 200/error response
SyncScript-->>Orchestration: Report success/failure
Orchestration->>SyncScript: Execute sync-filters.sh (if filters.json changed)
SyncScript->>JiraAPI: PUT /rest/api/2/filter/{id}
JiraAPI-->>SyncScript: HTTP response
SyncScript-->>Orchestration: Report result
Orchestration->>SyncScript: Execute sync-projects.sh (if projects.json changed)
SyncScript->>JiraAPI: PUT /rest/api/2/project/{key}
JiraAPI-->>SyncScript: HTTP response
SyncScript-->>Orchestration: Report result
Orchestration->>SyncScript: Execute sync-components.sh (if components.json changed)
SyncScript->>JiraAPI: PUT /rest/api/2/component/{id}
JiraAPI-->>SyncScript: HTTP response
SyncScript-->>Orchestration: Report result
Orchestration-->>Workflow: Exit with aggregate status
Workflow-->>GitHub: Workflow complete
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
/hold for review and secrets |
There was a problem hiding this comment.
Actionable comments posted: 12
🧹 Nitpick comments (4)
edge-scrum/.jira-config/boards.json (1)
13-19: Empty properties object — confirm this is intentional.The "OCPEDGE Scrum" board has an empty
propertiesobject, while the other two boards explicitly configure roadmap and child-issue planning properties.If default board settings are appropriate for this board, consider adding a comment to make this explicit. If properties should be configured, please add them for consistency.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@edge-scrum/.jira-config/boards.json` around lines 13 - 19, The "OCPEDGE Scrum" board entry (id "8557", name "OCPEDGE Scrum") has an empty properties object; either make this explicit by adding a comment indicating default settings are intentional or align it with the other boards by populating the properties field with the same roadmap/child-issue planning keys used elsewhere (copy the properties structure from the other board entries and adjust values as needed) so the configuration is consistent..github/workflows/jira-sync-pr.yml (1)
36-48: Document why credentials are required for dry-run and explain fork PR behavior.The dry-run job requires Jira credentials because the sync scripts validate
JIRA_USERNAMEandJIRA_API_TOKENupfront (even though actual API requests aren't made in dry-run mode). This means:
- PRs from forks won't have access to secrets and will fail at the credential validation step
- The error message is clear (
JIRA_USERNAME must be set), but the reason isn't obviousConsider adding a workflow comment or README section explaining why credentials are validated even for dry-run previews and noting that fork PRs will fail at this step due to GitHub's security model for secrets access.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/jira-sync-pr.yml around lines 36 - 48, Add documentation near the dry-run job (job name "dry-run") explaining that the script edge-scrum/.ci/scripts/apply-changes.sh performs upfront validation of JIRA_USERNAME and JIRA_API_TOKEN even in --dry-run mode, and therefore GitHub Actions secrets are required; also note that PRs from forks will not have access to these secrets and will fail at the credential validation step due to GitHub's secrets security model. Update the workflow file with a brief inline comment above the env block for JIRA_USERNAME/JIRA_API_TOKEN and/or add a short note to the repo README/CI docs describing this fork-PR behavior and suggested alternatives (e.g., running the preview locally or enabling a bot account).edge-scrum/.ci/scripts/apply-changes.sh (1)
10-10: Remove unusedJIRA_CONFIG_DIRvariable.
JIRA_CONFIG_DIRis declared on Line 10 but never used; dropping it will keep the script tighter and avoid ShellCheck noise.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@edge-scrum/.ci/scripts/apply-changes.sh` at line 10, Remove the unused shell variable by deleting the JIRA_CONFIG_DIR declaration (JIRA_CONFIG_DIR="${EDGE_SCRUM_DIR}/.jira-config") since it is never referenced elsewhere; ensure no other code relies on JIRA_CONFIG_DIR and run a quick ShellCheck to confirm no remaining warnings related to this variable.edge-scrum/.ci/scripts/validate-readme-sync.sh (1)
10-10: Drop unused variables in README sync validator.
README_FILE(Line 10) andfile_path(Line 43) are not read afterward; removing them will reduce dead code and ShellCheck warnings.Also applies to: 43-43
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@edge-scrum/.ci/scripts/validate-readme-sync.sh` at line 10, Remove the dead variables by deleting the README_FILE assignment and the unused file_path variable in the validate-readme-sync.sh script; search for README_FILE and file_path and remove their declarations and any dead references (or replace with the correct variable/path if they were meant to be used), then run ShellCheck to confirm warnings are gone and the script still functions with the remaining variables and logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@edge-scrum/.ci/README.md`:
- Around line 124-142: The README currently instructs contributors to create and
load credentials from edge-scrum/.env, but the CI scripts read from the process
environment and do not source that file; update the docs to remove the cat >
edge-scrum/.env example and the claim “Load from edge-scrum/.env” and instead
instruct users to export the required environment variables (JIRA_URL,
JIRA_USERNAME, JIRA_API_TOKEN) into their shell or CI secret store so the
scripts that read process env vars will see them; keep wording consistent with
the PR’s env-only secret handling and mention the exact variable names
(JIRA_URL, JIRA_USERNAME, JIRA_API_TOKEN) referenced in the scripts.
In `@edge-scrum/.ci/schemas/filters.schema.json`:
- Around line 4-29: The permission schema currently only enforces required
fields when permission.type === "group", letting invalid shapes for other types
(user, project, role, authenticated, global) pass validation and fail later;
update the "permission" definition to validate each variant explicitly by adding
additional conditional branches (if/then) or a oneOf that ties type values to
their required properties (e.g., when type === "user" require a "user" object
with its expected fields, when type === "project" require a "project" object,
when type === "role" require a "role" object, and for "authenticated"/"global"
disallow extraneous variant objects), and ensure extraneous properties are
disallowed for each variant so sync-filters.sh receives correctly-shaped
payloads (refer to the "permission" object, its "type" property, and the
existing if/then logic to extend).
In `@edge-scrum/.ci/schemas/projects.schema.json`:
- Around line 45-47: The schema currently marks "roles" as required but only
declares "type": "array" without any item schema and the sync logic (see
projects.json sync) ignores roles; either remove the "roles" property and its
required entry from projects.schema.json if roles are not implemented, or
replace the loose declaration with a proper items definition (e.g., an array of
objects with required fields like "name", "actor", "accountId"/"account_id", and
any allowed enums) and update any corresponding validation code used by the sync
script so the structure is enforced and actually applied during sync (refer to
the "roles" property and the sync handling in projects.json to keep names
consistent).
In `@edge-scrum/.ci/scripts/sync-boards.sh`:
- Around line 121-126: The curl call that sets HTTP_CODE in sync-boards.sh can
block indefinitely; update the invocation that writes to
"${TMPDIR}/response.json" to include connection and overall timeouts and retry
controls (e.g., --connect-timeout, --max-time, --retry, --retry-delay and
--retry-connrefused) so PUTs to
"${JIRA_URL}/rest/agile/1.0/board/${BOARD_ID}/properties/${PROPERTY_KEY}" using
${JIRA_AUTH} and ${PROPERTY_VALUE} will fail fast and retry transient errors
instead of hanging the CI job.
In `@edge-scrum/.ci/scripts/sync-components.sh`:
- Line 76: Replace fragile jq array iteration that uses '.components[]' /
'.projects[]' (seen in the COMPONENTS and PROJECTS assignments and the other jq
calls) with a safe, empty-aware form so jq won't fail on empty arrays;
specifically change occurrences like COMPONENTS=$(jq -c '.components[]'
"${CONFIG_FILE}") and PROJECTS=$(jq -c '.projects[]' ...) to use the safe
operator '?', e.g. COMPONENTS=$(jq -c '.components[]?' "${CONFIG_FILE}") and
PROJECTS=$(jq -c '.projects[]?' "${CONFIG_FILE}"), and apply the same change to
the other jq invocations around the mentioned regions (lines handling
components/projects) to prevent jq from exiting with an error on empty input.
- Around line 128-133: The curl PUT that sets HTTP_CODE can hang; update the
curl invocation that uses UPDATE_PAYLOAD, COMPONENT_ID and JIRA_URL (the command
assigning HTTP_CODE) to include network hardening: set connection and overall
timeouts (e.g., --connect-timeout and --max-time), enable automatic retries for
transient failures (e.g., --retry, --retry-delay and --retry-connrefused) and
fail fast on HTTP errors (e.g., --fail) so the CI job won’t block indefinitely
and will surface transient errors reliably.
In `@edge-scrum/.ci/scripts/sync-filters.sh`:
- Line 207: The post-increment expression used to advance the loop counter (the
((index++)) expression) returns a non-zero exit status under set -euo pipefail
on the first iteration and aborts the script; replace that post-increment with a
form that yields a zero exit status (e.g., a pre-increment or an explicit
addition assignment) so the loop can continue, updating the single use of the
index increment expression in the loop where index is advanced.
- Around line 140-145: The curl call that sets `response=$(curl -s -w
"\n%{http_code}" -X PUT ... -d "$payload"
"${JIRA_URL}/rest/api/2/filter/${filter_id}")` needs bounded timeouts and retry
behavior to avoid hangs; update this invocation to include connect and overall
timeouts (e.g., --connect-timeout and --max-time), enable controlled retries
(e.g., --retry N, --retry-delay SECONDS and/or --retry-max-time), and surface
errors (e.g., --fail --show-error) so transient network failures are retried and
permanent failures return a non-zero exit code; after the call, check curl's
exit status and the HTTP status code in `response` and handle retry/failure
accordingly.
In `@edge-scrum/.ci/scripts/sync-projects.sh`:
- Around line 149-154: The curl call that assigns response in sync-projects.sh
currently has no timeout or retry controls and can hang; update the curl
invocation that assigns the response variable to include connection and total
timeouts and retries by adding the flags --connect-timeout 10 --max-time 60
--retry 3 --retry-all-errors so the PUT to
"${JIRA_URL}/rest/api/2/project/${project_key}" (using JIRA_AUTH and payload)
fails fast and retries transient errors.
In `@edge-scrum/.ci/scripts/validate-configs.sh`:
- Around line 82-86: The duplicate-name check is missing for
boards/filters/projects: update the validation calls so each of boards.json,
filters.json and projects.json is also checked for unique "name" values (in
addition to "id") by invoking the same validation routine used for
components/labels; specifically add calls to validate_file for
"${CONFIG_DIR}/boards.json", "${CONFIG_DIR}/filters.json", and
"${CONFIG_DIR}/projects.json" with the corresponding schema variables and "name"
as the uniqueness key (same pattern used for components.json/labels.json), or
extend the validate_file implementation to accept and run uniqueness checks for
both "id" and "name" when present.
In `@edge-scrum/.jira-config/filters.json`:
- Line 227: The JQL in the "jql" string incorrectly mixes OR and AND without
grouping, so the assignment/status constraints only apply to the last filter;
update the query in the jql value to add explicit parentheses so the AND clause
applies to all intended sources (wrap the OR-connected sources — e.g., project
in (USHIFT, OCPEDGE) OR filter = "OpenShift Edge - Core Backlog" OR filter in
("OpenShift Edge - External Projects", "OpenShift Edge - Bugs and CVEs") — in
parens, then append AND (filter = "OpenShift Edge - Team Assigned" OR (filter =
"OpenShift Edge - QE Assigned" AND status in (...))) to ensure correct
precedence).
In `@edge-scrum/.jira-config/projects.json`:
- Around line 14-153: projects.json contains a large "roles" block that is not
synced by the tooling (sync-projects.sh acknowledges this and update_project()
only syncs name/description/leadAccountId/assigneeType), causing configuration
drift and confusion; either remove the entire "roles" field from projects.json
and move role setup instructions into README.md, or add a prominent inline
comment above the "roles" array in projects.json stating "UI-only — not managed
by sync-projects.sh / update_project()" and document the manual Jira UI steps in
README.md (ensure README.md cross-references sync-projects.sh and
update_project()).
---
Nitpick comments:
In @.github/workflows/jira-sync-pr.yml:
- Around line 36-48: Add documentation near the dry-run job (job name "dry-run")
explaining that the script edge-scrum/.ci/scripts/apply-changes.sh performs
upfront validation of JIRA_USERNAME and JIRA_API_TOKEN even in --dry-run mode,
and therefore GitHub Actions secrets are required; also note that PRs from forks
will not have access to these secrets and will fail at the credential validation
step due to GitHub's secrets security model. Update the workflow file with a
brief inline comment above the env block for JIRA_USERNAME/JIRA_API_TOKEN and/or
add a short note to the repo README/CI docs describing this fork-PR behavior and
suggested alternatives (e.g., running the preview locally or enabling a bot
account).
In `@edge-scrum/.ci/scripts/apply-changes.sh`:
- Line 10: Remove the unused shell variable by deleting the JIRA_CONFIG_DIR
declaration (JIRA_CONFIG_DIR="${EDGE_SCRUM_DIR}/.jira-config") since it is never
referenced elsewhere; ensure no other code relies on JIRA_CONFIG_DIR and run a
quick ShellCheck to confirm no remaining warnings related to this variable.
In `@edge-scrum/.ci/scripts/validate-readme-sync.sh`:
- Line 10: Remove the dead variables by deleting the README_FILE assignment and
the unused file_path variable in the validate-readme-sync.sh script; search for
README_FILE and file_path and remove their declarations and any dead references
(or replace with the correct variable/path if they were meant to be used), then
run ShellCheck to confirm warnings are gone and the script still functions with
the remaining variables and logic.
In `@edge-scrum/.jira-config/boards.json`:
- Around line 13-19: The "OCPEDGE Scrum" board entry (id "8557", name "OCPEDGE
Scrum") has an empty properties object; either make this explicit by adding a
comment indicating default settings are intentional or align it with the other
boards by populating the properties field with the same roadmap/child-issue
planning keys used elsewhere (copy the properties structure from the other board
entries and adjust values as needed) so the configuration is consistent.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f8d2386e-92af-4172-908b-af241a110599
📒 Files selected for processing (23)
.github/workflows/jira-sync-apply.yml.github/workflows/jira-sync-pr.yml.gitignoreedge-scrum/.ci/README.mdedge-scrum/.ci/schemas/boards.schema.jsonedge-scrum/.ci/schemas/components.schema.jsonedge-scrum/.ci/schemas/filters.schema.jsonedge-scrum/.ci/schemas/labels.schema.jsonedge-scrum/.ci/schemas/projects.schema.jsonedge-scrum/.ci/scripts/apply-changes.shedge-scrum/.ci/scripts/sync-boards.shedge-scrum/.ci/scripts/sync-components.shedge-scrum/.ci/scripts/sync-filters.shedge-scrum/.ci/scripts/sync-projects.shedge-scrum/.ci/scripts/validate-configs.shedge-scrum/.ci/scripts/validate-readme-sync.shedge-scrum/.jira-config/README.mdedge-scrum/.jira-config/boards.jsonedge-scrum/.jira-config/components.jsonedge-scrum/.jira-config/filters.jsonedge-scrum/.jira-config/labels.jsonedge-scrum/.jira-config/projects.jsonedge-scrum/README.md
| - **Credentials:** Load from `edge-scrum/.env` (JIRA_URL, JIRA_USERNAME, JIRA_API_TOKEN) | ||
| - **Error handling:** Exit with code 1 if any updates fail | ||
| - **Validation:** Check prerequisites (jq, curl, config files, env vars) | ||
| - **Logging:** Clear, color-coded output showing what's being updated | ||
| - **Safety:** Only update existing entities (no create/delete operations) | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| ```bash | ||
| # Install dependencies | ||
| sudo dnf install jq curl git # Fedora/RHEL | ||
| sudo apt install jq curl git # Debian/Ubuntu | ||
|
|
||
| # Configure credentials | ||
| cat > edge-scrum/.env <<EOF | ||
| export JIRA_URL="https://redhat.atlassian.net" | ||
| export JIRA_USERNAME="your-email@redhat.com" | ||
| export JIRA_API_TOKEN="your-api-token" | ||
| EOF |
There was a problem hiding this comment.
Credential setup docs are inconsistent with script behavior and PR security model.
At Line 124 and Line 138-Line 142, the README says credentials are loaded from .env, but these scripts read process environment variables and do not source that file. This can mislead contributors and conflicts with the env-only secret handling described in this PR.
📝 Suggested documentation correction
-- **Credentials:** Load from `edge-scrum/.env` (JIRA_URL, JIRA_USERNAME, JIRA_API_TOKEN)
+- **Credentials:** Provide as environment variables (JIRA_URL, JIRA_USERNAME, JIRA_API_TOKEN)
@@
-# Configure credentials
-cat > edge-scrum/.env <<EOF
-export JIRA_URL="https://redhat.atlassian.net"
-export JIRA_USERNAME="your-email@redhat.com"
-export JIRA_API_TOKEN="your-api-token"
-EOF
+# Configure credentials for current shell/session
+export JIRA_URL="https://redhat.atlassian.net"
+export JIRA_USERNAME="your-email@redhat.com"
+export JIRA_API_TOKEN="your-api-token"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@edge-scrum/.ci/README.md` around lines 124 - 142, The README currently
instructs contributors to create and load credentials from edge-scrum/.env, but
the CI scripts read from the process environment and do not source that file;
update the docs to remove the cat > edge-scrum/.env example and the claim “Load
from edge-scrum/.env” and instead instruct users to export the required
environment variables (JIRA_URL, JIRA_USERNAME, JIRA_API_TOKEN) into their shell
or CI secret store so the scripts that read process env vars will see them; keep
wording consistent with the PR’s env-only secret handling and mention the exact
variable names (JIRA_URL, JIRA_USERNAME, JIRA_API_TOKEN) referenced in the
scripts.
| "permission": { | ||
| "type": "object", | ||
| "required": ["type"], | ||
| "properties": { | ||
| "type": { | ||
| "type": "string", | ||
| "enum": ["group", "user", "authenticated", "project", "role", "global"] | ||
| }, | ||
| "group": { | ||
| "type": "object", | ||
| "required": ["name"], | ||
| "properties": { | ||
| "name": { "type": "string", "minLength": 1 } | ||
| } | ||
| }, | ||
| "user": { | ||
| "type": "object" | ||
| } | ||
| }, | ||
| "if": { | ||
| "properties": { "type": { "const": "group" } } | ||
| }, | ||
| "then": { | ||
| "required": ["group"] | ||
| } | ||
| } |
There was a problem hiding this comment.
Harden permission variant validation to prevent CI-pass/runtime-fail payloads.
At Line 4-Line 29, permission accepts multiple type values but only enforces required fields for group. That allows invalid user/project/role shapes through schema validation, then fails later when sync-filters.sh sends them to Jira.
🔧 Proposed schema tightening
"permission": {
"type": "object",
+ "additionalProperties": false,
"required": ["type"],
"properties": {
"type": {
"type": "string",
"enum": ["group", "user", "authenticated", "project", "role", "global"]
},
"group": {
"type": "object",
+ "additionalProperties": false,
"required": ["name"],
"properties": {
"name": { "type": "string", "minLength": 1 }
}
},
- "user": {
- "type": "object"
- }
- },
- "if": {
- "properties": { "type": { "const": "group" } }
- },
- "then": {
- "required": ["group"]
- }
+ "user": { "type": "object", "required": ["accountId"], "properties": { "accountId": { "type": "string", "minLength": 1 } }, "additionalProperties": false },
+ "project": { "type": "object", "required": ["id"], "properties": { "id": { "type": "string", "pattern": "^[0-9]+$" } }, "additionalProperties": false },
+ "role": { "type": "object", "required": ["id"], "properties": { "id": { "type": "string", "pattern": "^[0-9]+$" } }, "additionalProperties": false }
+ },
+ "allOf": [
+ { "if": { "properties": { "type": { "const": "group" } } }, "then": { "required": ["group"] } },
+ { "if": { "properties": { "type": { "const": "user" } } }, "then": { "required": ["user"] } },
+ { "if": { "properties": { "type": { "const": "project" } } }, "then": { "required": ["project"] } },
+ { "if": { "properties": { "type": { "const": "role" } } }, "then": { "required": ["role"] } }
+ ]
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "permission": { | |
| "type": "object", | |
| "required": ["type"], | |
| "properties": { | |
| "type": { | |
| "type": "string", | |
| "enum": ["group", "user", "authenticated", "project", "role", "global"] | |
| }, | |
| "group": { | |
| "type": "object", | |
| "required": ["name"], | |
| "properties": { | |
| "name": { "type": "string", "minLength": 1 } | |
| } | |
| }, | |
| "user": { | |
| "type": "object" | |
| } | |
| }, | |
| "if": { | |
| "properties": { "type": { "const": "group" } } | |
| }, | |
| "then": { | |
| "required": ["group"] | |
| } | |
| } | |
| "permission": { | |
| "type": "object", | |
| "additionalProperties": false, | |
| "required": ["type"], | |
| "properties": { | |
| "type": { | |
| "type": "string", | |
| "enum": ["group", "user", "authenticated", "project", "role", "global"] | |
| }, | |
| "group": { | |
| "type": "object", | |
| "additionalProperties": false, | |
| "required": ["name"], | |
| "properties": { | |
| "name": { "type": "string", "minLength": 1 } | |
| } | |
| }, | |
| "user": { "type": "object", "required": ["accountId"], "properties": { "accountId": { "type": "string", "minLength": 1 } }, "additionalProperties": false }, | |
| "project": { "type": "object", "required": ["id"], "properties": { "id": { "type": "string", "pattern": "^[0-9]+$" } }, "additionalProperties": false }, | |
| "role": { "type": "object", "required": ["id"], "properties": { "id": { "type": "string", "pattern": "^[0-9]+$" } }, "additionalProperties": false } | |
| }, | |
| "allOf": [ | |
| { "if": { "properties": { "type": { "const": "group" } } }, "then": { "required": ["group"] } }, | |
| { "if": { "properties": { "type": { "const": "user" } } }, "then": { "required": ["user"] } }, | |
| { "if": { "properties": { "type": { "const": "project" } } }, "then": { "required": ["project"] } }, | |
| { "if": { "properties": { "type": { "const": "role" } } }, "then": { "required": ["role"] } } | |
| ] | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@edge-scrum/.ci/schemas/filters.schema.json` around lines 4 - 29, The
permission schema currently only enforces required fields when permission.type
=== "group", letting invalid shapes for other types (user, project, role,
authenticated, global) pass validation and fail later; update the "permission"
definition to validate each variant explicitly by adding additional conditional
branches (if/then) or a oneOf that ties type values to their required properties
(e.g., when type === "user" require a "user" object with its expected fields,
when type === "project" require a "project" object, when type === "role" require
a "role" object, and for "authenticated"/"global" disallow extraneous variant
objects), and ensure extraneous properties are disallowed for each variant so
sync-filters.sh receives correctly-shaped payloads (refer to the "permission"
object, its "type" property, and the existing if/then logic to extend).
| "roles": { | ||
| "type": "array" | ||
| } |
There was a problem hiding this comment.
Roles field required but not validated or synced.
The schema requires roles (line 12) but defines it only as "type": "array" with no structure validation. This is problematic because:
- No validation: Users can put arbitrary data in the roles array without any schema constraints on role objects, actors, account IDs, etc.
- Not synced: The sync script ignores roles entirely (see
projects.jsonreview comment). - Misleading: Marking as required suggests it's important, but it's neither validated nor applied.
This compounds the issue flagged in projects.json — the role configuration appears to be managed through config-as-code but is actually non-functional.
Recommended fix: Align the schema with the actual sync behavior:
Option 1: Remove roles from schema (if not implementing sync)
- "required": ["id", "key", "name", "description", "assigneeType", "lead", "roles"],
+ "required": ["id", "key", "name", "description", "assigneeType", "lead"],
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"pattern": "^[0-9]+$"
},
...
"lead": {
"type": "object",
"required": ["id", "email"],
"properties": {
"id": { "type": "string", "minLength": 1 },
"email": { "type": "string", "pattern": ".+@.+" }
}
- },
- "roles": {
- "type": "array"
}
}Option 2: Properly validate roles structure (if keeping for reference)
"roles": {
- "type": "array"
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": ["id", "name"],
+ "properties": {
+ "id": { "type": "string" },
+ "name": { "type": "string" },
+ "description": { "type": "string" },
+ "actors": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": ["type"],
+ "properties": {
+ "type": { "type": "string" },
+ "account_id": { "type": "string" },
+ "group_id": { "type": "string" },
+ "display_name": { "type": "string" },
+ "group_name": { "type": "string" }
+ }
+ }
+ }
+ }
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "roles": { | |
| "type": "array" | |
| } | |
| "roles": { | |
| "type": "array", | |
| "items": { | |
| "type": "object", | |
| "required": ["id", "name"], | |
| "properties": { | |
| "id": { "type": "string" }, | |
| "name": { "type": "string" }, | |
| "description": { "type": "string" }, | |
| "actors": { | |
| "type": "array", | |
| "items": { | |
| "type": "object", | |
| "required": ["type"], | |
| "properties": { | |
| "type": { "type": "string" }, | |
| "account_id": { "type": "string" }, | |
| "group_id": { "type": "string" }, | |
| "display_name": { "type": "string" }, | |
| "group_name": { "type": "string" } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@edge-scrum/.ci/schemas/projects.schema.json` around lines 45 - 47, The schema
currently marks "roles" as required but only declares "type": "array" without
any item schema and the sync logic (see projects.json sync) ignores roles;
either remove the "roles" property and its required entry from
projects.schema.json if roles are not implemented, or replace the loose
declaration with a proper items definition (e.g., an array of objects with
required fields like "name", "actor", "accountId"/"account_id", and any allowed
enums) and update any corresponding validation code used by the sync script so
the structure is enforced and actually applied during sync (refer to the "roles"
property and the sync handling in projects.json to keep names consistent).
| HTTP_CODE=$(curl -s -w "%{http_code}" -o "${TMPDIR}/response.json" \ | ||
| -X PUT \ | ||
| -H "Content-Type: application/json" \ | ||
| -H "Authorization: Basic ${JIRA_AUTH}" \ | ||
| -d "${PROPERTY_VALUE}" \ | ||
| "${JIRA_URL}/rest/agile/1.0/board/${BOARD_ID}/properties/${PROPERTY_KEY}") |
There was a problem hiding this comment.
Add timeout/retry controls to Jira API calls.
Line 121 currently allows indefinite blocking on network stalls. In CI automation, this can wedge the whole sync job.
Suggested hardening for curl invocation
- HTTP_CODE=$(curl -s -w "%{http_code}" -o "${TMPDIR}/response.json" \
+ HTTP_CODE=$(curl -sS -w "%{http_code}" -o "${TMPDIR}/response.json" \
+ --connect-timeout 10 \
+ --max-time 60 \
+ --retry 3 \
+ --retry-delay 2 \
+ --retry-connrefused \
-X PUT \
-H "Content-Type: application/json" \
-H "Authorization: Basic ${JIRA_AUTH}" \
-d "${PROPERTY_VALUE}" \
"${JIRA_URL}/rest/agile/1.0/board/${BOARD_ID}/properties/${PROPERTY_KEY}")📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| HTTP_CODE=$(curl -s -w "%{http_code}" -o "${TMPDIR}/response.json" \ | |
| -X PUT \ | |
| -H "Content-Type: application/json" \ | |
| -H "Authorization: Basic ${JIRA_AUTH}" \ | |
| -d "${PROPERTY_VALUE}" \ | |
| "${JIRA_URL}/rest/agile/1.0/board/${BOARD_ID}/properties/${PROPERTY_KEY}") | |
| HTTP_CODE=$(curl -sS -w "%{http_code}" -o "${TMPDIR}/response.json" \ | |
| --connect-timeout 10 \ | |
| --max-time 60 \ | |
| --retry 3 \ | |
| --retry-delay 2 \ | |
| --retry-connrefused \ | |
| -X PUT \ | |
| -H "Content-Type: application/json" \ | |
| -H "Authorization: Basic ${JIRA_AUTH}" \ | |
| -d "${PROPERTY_VALUE}" \ | |
| "${JIRA_URL}/rest/agile/1.0/board/${BOARD_ID}/properties/${PROPERTY_KEY}") |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@edge-scrum/.ci/scripts/sync-boards.sh` around lines 121 - 126, The curl call
that sets HTTP_CODE in sync-boards.sh can block indefinitely; update the
invocation that writes to "${TMPDIR}/response.json" to include connection and
overall timeouts and retry controls (e.g., --connect-timeout, --max-time,
--retry, --retry-delay and --retry-connrefused) so PUTs to
"${JIRA_URL}/rest/agile/1.0/board/${BOARD_ID}/properties/${PROPERTY_KEY}" using
${JIRA_AUTH} and ${PROPERTY_VALUE} will fail fast and retry transient errors
instead of hanging the CI job.
| UPDATE_FAILED=false | ||
|
|
||
| # Read components from config file | ||
| COMPONENTS=$(jq -c '.components[]' "${CONFIG_FILE}") |
There was a problem hiding this comment.
Empty arrays can trigger jq parse failures and abort the sync.
With set -euo pipefail, using COMPONENTS=$(jq -c '.components[]' ...) / PROJECTS=$(jq -c '.projects[]') plus here-strings can execute one empty iteration and make jq fail on blank input.
Suggested robust iteration pattern
-COMPONENTS=$(jq -c '.components[]' "${CONFIG_FILE}")
+COMPONENTS_CMD=(jq -c '.components[]?' "${CONFIG_FILE}")
@@
-while IFS= read -r component; do
+while IFS= read -r component; do
COMPONENT_NAME=$(echo "${component}" | jq -r '.name')
COMPONENT_DESC=$(echo "${component}" | jq -r '.description')
@@
- PROJECTS=$(echo "${component}" | jq -c '.projects[]')
-
- while IFS= read -r project; do
+ while IFS= read -r project; do
COMPONENT_ID=$(echo "${project}" | jq -r '.component_id // empty')
PROJECT_KEY=$(echo "${project}" | jq -r '.project_key')
@@
- done <<< "${PROJECTS}"
+ done < <(jq -c '.projects[]?' <<< "${component}")
@@
-done <<< "${COMPONENTS}"
+done < <("${COMPONENTS_CMD[@]}")Also applies to: 92-92, 100-103, 145-149
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@edge-scrum/.ci/scripts/sync-components.sh` at line 76, Replace fragile jq
array iteration that uses '.components[]' / '.projects[]' (seen in the
COMPONENTS and PROJECTS assignments and the other jq calls) with a safe,
empty-aware form so jq won't fail on empty arrays; specifically change
occurrences like COMPONENTS=$(jq -c '.components[]' "${CONFIG_FILE}") and
PROJECTS=$(jq -c '.projects[]' ...) to use the safe operator '?', e.g.
COMPONENTS=$(jq -c '.components[]?' "${CONFIG_FILE}") and PROJECTS=$(jq -c
'.projects[]?' "${CONFIG_FILE}"), and apply the same change to the other jq
invocations around the mentioned regions (lines handling components/projects) to
prevent jq from exiting with an error on empty input.
| exit_code=1 | ||
| fi | ||
|
|
||
| ((index++)) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify the risky increment pattern exists
rg -n '\(\(index\+\+\)\)' edge-scrum/.ci/scripts/sync-filters.sh
# Reproduce bash behavior under set -e (expected: early non-zero)
if bash -c 'set -e; i=0; ((i++)); echo "UNEXPECTED_REACHABLE"'; then
echo "Unexpected: command did not fail"
exit 1
else
echo "Expected: post-increment returned non-zero and aborted under set -e"
fiRepository: openshift-eng/edge-tooling
Length of output: 161
🏁 Script executed:
# Check if set -euo pipefail is in the script
head -20 edge-scrum/.ci/scripts/sync-filters.sh | grep -n "set"
# Get context around line 207 (10 lines before and after)
sed -n '197,217p' edge-scrum/.ci/scripts/sync-filters.sh | cat -n | sed 's/^[[:space:]]*//' | awk '{print NR+196 ": " $0}'Repository: openshift-eng/edge-tooling
Length of output: 1043
🏁 Script executed:
# Get broader context to see the loop initialization
sed -n '180,210p' edge-scrum/.ci/scripts/sync-filters.sh | cat -n | awk '{print NR+179 ": " $0}'Repository: openshift-eng/edge-tooling
Length of output: 1531
set -e + ((index++)) terminates the script on the first loop iteration.
At Line 207, post-increment in a (( )) command evaluates to 0 on the first iteration, causing an exit code of 1 under set -euo pipefail (set at line 19). This aborts the script before it can process any filters.
🐛 Safe increment fix
- ((index++))
+ ((++index))Pre-increment (++index) returns 1 on the first iteration, yielding exit code 0 and allowing the loop to continue.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ((index++)) | |
| ((++index)) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@edge-scrum/.ci/scripts/sync-filters.sh` at line 207, The post-increment
expression used to advance the loop counter (the ((index++)) expression) returns
a non-zero exit status under set -euo pipefail on the first iteration and aborts
the script; replace that post-increment with a form that yields a zero exit
status (e.g., a pre-increment or an explicit addition assignment) so the loop
can continue, updating the single use of the index increment expression in the
loop where index is advanced.
| response=$(curl -s -w "\n%{http_code}" \ | ||
| -X PUT \ | ||
| -H "Content-Type: application/json" \ | ||
| -H "Authorization: Basic ${JIRA_AUTH}" \ | ||
| -d "${payload}" \ | ||
| "${JIRA_URL}/rest/api/2/project/${project_key}") |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify timeout/retry flags are currently absent/present in this file
rg -n 'curl -s -w "\\n%\\{http_code\\}"' edge-scrum/.ci/scripts/sync-projects.sh
rg -n -- '--connect-timeout|--max-time|--retry|--retry-all-errors' edge-scrum/.ci/scripts/sync-projects.shRepository: openshift-eng/edge-tooling
Length of output: 203
🏁 Script executed:
#!/bin/bash
# Read the specific lines from the file
echo "=== Lines 149-154 from sync-projects.sh ==="
sed -n '149,154p' edge-scrum/.ci/scripts/sync-projects.sh
echo -e "\n=== All curl commands in sync-projects.sh ==="
rg -n 'curl' edge-scrum/.ci/scripts/sync-projects.sh -A 3
echo -e "\n=== Checking for timeout flags anywhere in sync-projects.sh ==="
rg -n 'connect-timeout|max-time|--retry' edge-scrum/.ci/scripts/sync-projects.sh
echo -e "\n=== Total file length ==="
wc -l edge-scrum/.ci/scripts/sync-projects.shRepository: openshift-eng/edge-tooling
Length of output: 952
Bind project update calls with timeout and retry controls.
At lines 149-154, this external Jira API write has no timeout. A stuck network path can block the workflow run indefinitely. Add --connect-timeout 10 --max-time 60 --retry 3 --retry-all-errors flags to the curl command:
🔧 Proposed fix
- response=$(curl -s -w "\n%{http_code}" \
+ response=$(curl -s -w "\n%{http_code}" \
+ --connect-timeout 10 \
+ --max-time 60 \
+ --retry 3 \
+ --retry-all-errors \
-X PUT \
-H "Content-Type: application/json" \
-H "Authorization: Basic ${JIRA_AUTH}" \
-d "${payload}" \
"${JIRA_URL}/rest/api/2/project/${project_key}")📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| response=$(curl -s -w "\n%{http_code}" \ | |
| -X PUT \ | |
| -H "Content-Type: application/json" \ | |
| -H "Authorization: Basic ${JIRA_AUTH}" \ | |
| -d "${payload}" \ | |
| "${JIRA_URL}/rest/api/2/project/${project_key}") | |
| response=$(curl -s -w "\n%{http_code}" \ | |
| --connect-timeout 10 \ | |
| --max-time 60 \ | |
| --retry 3 \ | |
| --retry-all-errors \ | |
| -X PUT \ | |
| -H "Content-Type: application/json" \ | |
| -H "Authorization: Basic ${JIRA_AUTH}" \ | |
| -d "${payload}" \ | |
| "${JIRA_URL}/rest/api/2/project/${project_key}") |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@edge-scrum/.ci/scripts/sync-projects.sh` around lines 149 - 154, The curl
call that assigns response in sync-projects.sh currently has no timeout or retry
controls and can hang; update the curl invocation that assigns the response
variable to include connection and total timeouts and retries by adding the
flags --connect-timeout 10 --max-time 60 --retry 3 --retry-all-errors so the PUT
to "${JIRA_URL}/rest/api/2/project/${project_key}" (using JIRA_AUTH and payload)
fails fast and retries transient errors.
| validate_file "${CONFIG_DIR}/boards.json" "${SCHEMA_DIR}/boards.schema.json" "boards" "id" | ||
| validate_file "${CONFIG_DIR}/filters.json" "${SCHEMA_DIR}/filters.schema.json" "filters" "id" | ||
| validate_file "${CONFIG_DIR}/projects.json" "${SCHEMA_DIR}/projects.schema.json" "projects" "id" | ||
| validate_file "${CONFIG_DIR}/components.json" "${SCHEMA_DIR}/components.schema.json" "components" "name" | ||
| validate_file "${CONFIG_DIR}/labels.json" "${SCHEMA_DIR}/labels.schema.json" "labels" "name" |
There was a problem hiding this comment.
Duplicate-name validation is missing for several config types.
Lines 82-84 validate only id uniqueness for boards/filters/projects, so duplicate name values can slip through even though the PR objective calls for duplicate ID/name checks.
Suggested approach
- validate_file "${CONFIG_DIR}/boards.json" "${SCHEMA_DIR}/boards.schema.json" "boards" "id"
- validate_file "${CONFIG_DIR}/filters.json" "${SCHEMA_DIR}/filters.schema.json" "filters" "id"
- validate_file "${CONFIG_DIR}/projects.json" "${SCHEMA_DIR}/projects.schema.json" "projects" "id"
+ validate_file "${CONFIG_DIR}/boards.json" "${SCHEMA_DIR}/boards.schema.json" "boards" "id"
+ validate_file "${CONFIG_DIR}/boards.json" "${SCHEMA_DIR}/boards.schema.json" "boards" "name"
+ validate_file "${CONFIG_DIR}/filters.json" "${SCHEMA_DIR}/filters.schema.json" "filters" "id"
+ validate_file "${CONFIG_DIR}/filters.json" "${SCHEMA_DIR}/filters.schema.json" "filters" "name"
+ validate_file "${CONFIG_DIR}/projects.json" "${SCHEMA_DIR}/projects.schema.json" "projects" "id"
+ validate_file "${CONFIG_DIR}/projects.json" "${SCHEMA_DIR}/projects.schema.json" "projects" "name"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| validate_file "${CONFIG_DIR}/boards.json" "${SCHEMA_DIR}/boards.schema.json" "boards" "id" | |
| validate_file "${CONFIG_DIR}/filters.json" "${SCHEMA_DIR}/filters.schema.json" "filters" "id" | |
| validate_file "${CONFIG_DIR}/projects.json" "${SCHEMA_DIR}/projects.schema.json" "projects" "id" | |
| validate_file "${CONFIG_DIR}/components.json" "${SCHEMA_DIR}/components.schema.json" "components" "name" | |
| validate_file "${CONFIG_DIR}/labels.json" "${SCHEMA_DIR}/labels.schema.json" "labels" "name" | |
| validate_file "${CONFIG_DIR}/boards.json" "${SCHEMA_DIR}/boards.schema.json" "boards" "id" | |
| validate_file "${CONFIG_DIR}/boards.json" "${SCHEMA_DIR}/boards.schema.json" "boards" "name" | |
| validate_file "${CONFIG_DIR}/filters.json" "${SCHEMA_DIR}/filters.schema.json" "filters" "id" | |
| validate_file "${CONFIG_DIR}/filters.json" "${SCHEMA_DIR}/filters.schema.json" "filters" "name" | |
| validate_file "${CONFIG_DIR}/projects.json" "${SCHEMA_DIR}/projects.schema.json" "projects" "id" | |
| validate_file "${CONFIG_DIR}/projects.json" "${SCHEMA_DIR}/projects.schema.json" "projects" "name" | |
| validate_file "${CONFIG_DIR}/components.json" "${SCHEMA_DIR}/components.schema.json" "components" "name" | |
| validate_file "${CONFIG_DIR}/labels.json" "${SCHEMA_DIR}/labels.schema.json" "labels" "name" |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@edge-scrum/.ci/scripts/validate-configs.sh` around lines 82 - 86, The
duplicate-name check is missing for boards/filters/projects: update the
validation calls so each of boards.json, filters.json and projects.json is also
checked for unique "name" values (in addition to "id") by invoking the same
validation routine used for components/labels; specifically add calls to
validate_file for "${CONFIG_DIR}/boards.json", "${CONFIG_DIR}/filters.json", and
"${CONFIG_DIR}/projects.json" with the corresponding schema variables and "name"
as the uniqueness key (same pattern used for components.json/labels.json), or
extend the validate_file implementation to accept and run uniqueness checks for
both "id" and "name" when present.
| "id": "104882", | ||
| "name": "OpenShift Edge - Scrum Board", | ||
| "description": "", | ||
| "jql": "project in (USHIFT, OCPEDGE) OR filter = \"OpenShift Edge - Core Backlog\" OR filter in (\"OpenShift Edge - External Projects\", \"OpenShift Edge - Bugs and CVEs\") AND (filter = \"OpenShift Edge - Team Assigned\" OR (filter = \"OpenShift Edge - QE Assigned\" AND status in (Review, MODIFIED, ON_QA, Testing))) ORDER BY Rank ASC", |
There was a problem hiding this comment.
Potentially incorrect JQL precedence in Scrum Board filter.
Line 227 mixes OR and AND without outer grouping, so assignment/status constraints are not consistently applied to all included sources. This can materially change board scope.
Suggested JQL grouping fix
- "jql": "project in (USHIFT, OCPEDGE) OR filter = \"OpenShift Edge - Core Backlog\" OR filter in (\"OpenShift Edge - External Projects\", \"OpenShift Edge - Bugs and CVEs\") AND (filter = \"OpenShift Edge - Team Assigned\" OR (filter = \"OpenShift Edge - QE Assigned\" AND status in (Review, MODIFIED, ON_QA, Testing))) ORDER BY Rank ASC",
+ "jql": "(project in (USHIFT, OCPEDGE) OR filter = \"OpenShift Edge - Core Backlog\" OR filter in (\"OpenShift Edge - External Projects\", \"OpenShift Edge - Bugs and CVEs\")) AND (filter = \"OpenShift Edge - Team Assigned\" OR (filter = \"OpenShift Edge - QE Assigned\" AND status in (Review, MODIFIED, ON_QA, Testing))) ORDER BY Rank ASC",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "jql": "project in (USHIFT, OCPEDGE) OR filter = \"OpenShift Edge - Core Backlog\" OR filter in (\"OpenShift Edge - External Projects\", \"OpenShift Edge - Bugs and CVEs\") AND (filter = \"OpenShift Edge - Team Assigned\" OR (filter = \"OpenShift Edge - QE Assigned\" AND status in (Review, MODIFIED, ON_QA, Testing))) ORDER BY Rank ASC", | |
| "jql": "(project in (USHIFT, OCPEDGE) OR filter = \"OpenShift Edge - Core Backlog\" OR filter in (\"OpenShift Edge - External Projects\", \"OpenShift Edge - Bugs and CVEs\")) AND (filter = \"OpenShift Edge - Team Assigned\" OR (filter = \"OpenShift Edge - QE Assigned\" AND status in (Review, MODIFIED, ON_QA, Testing))) ORDER BY Rank ASC", |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@edge-scrum/.jira-config/filters.json` at line 227, The JQL in the "jql"
string incorrectly mixes OR and AND without grouping, so the assignment/status
constraints only apply to the last filter; update the query in the jql value to
add explicit parentheses so the AND clause applies to all intended sources (wrap
the OR-connected sources — e.g., project in (USHIFT, OCPEDGE) OR filter =
"OpenShift Edge - Core Backlog" OR filter in ("OpenShift Edge - External
Projects", "OpenShift Edge - Bugs and CVEs") — in parens, then append AND
(filter = "OpenShift Edge - Team Assigned" OR (filter = "OpenShift Edge - QE
Assigned" AND status in (...))) to ensure correct precedence).
| "roles": [ | ||
| { | ||
| "id": "10002", | ||
| "name": "Administrators", | ||
| "description": "A project role that represents administrators in a project", | ||
| "actors": [ | ||
| { | ||
| "type": "atlassian-user-role-actor", | ||
| "account_id": "712020:93a6a685-d36f-4660-a64a-6870675c2ec8", | ||
| "display_name": "Chad Scribner" | ||
| }, | ||
| { | ||
| "type": "atlassian-user-role-actor", | ||
| "account_id": "712020:eca54813-6101-4bb6-b169-5b91a02029a1", | ||
| "display_name": "Jeff Roche" | ||
| }, | ||
| { | ||
| "type": "atlassian-user-role-actor", | ||
| "account_id": "70121:fd715ae6-c353-45e3-ab6d-4d856939baac", | ||
| "display_name": "Jeremy Poulin" | ||
| }, | ||
| { | ||
| "type": "atlassian-user-role-actor", | ||
| "account_id": "712020:188ebd21-393a-42a0-82dc-4646bc713e61", | ||
| "display_name": "Pablo Acevedo Montserrat" | ||
| }, | ||
| { | ||
| "type": "atlassian-user-role-actor", | ||
| "account_id": "61e811135fcc37006876d93a", | ||
| "display_name": "Gregory Giguashvili" | ||
| }, | ||
| { | ||
| "type": "atlassian-user-role-actor", | ||
| "account_id": "604a3e8543eac6006f8fbe82", | ||
| "display_name": "Nicole Wilker" | ||
| }, | ||
| { | ||
| "type": "atlassian-user-role-actor", | ||
| "account_id": "604bf97ce19f910069714b6c", | ||
| "display_name": "Sarah Kyros" | ||
| }, | ||
| { | ||
| "type": "atlassian-user-role-actor", | ||
| "account_id": "712020:06373c2b-9dbb-4310-b3c9-05b75997831c", | ||
| "display_name": "Suleyman Akbas" | ||
| }, | ||
| { | ||
| "type": "atlassian-group-role-actor", | ||
| "group_id": "21adff1a-e3a7-434f-a9e0-ad57c4f70762", | ||
| "group_name": "jira-administrators" | ||
| } | ||
| ] | ||
| }, | ||
| { | ||
| "id": "10125", | ||
| "name": "Users", | ||
| "description": "Standard user access", | ||
| "actors": [] | ||
| }, | ||
| { | ||
| "id": "10126", | ||
| "name": "Developers", | ||
| "description": "This project role is intended for anyone who is a team member, actively working in the Jira project. Developers cannot access the project settings, comments, and attachments that are not their own. They also do not have the ability to manage components, releases, or sprint information in the project. Developers do have the ability to start and complete sprints.", | ||
| "actors": [ | ||
| { | ||
| "type": "atlassian-user-role-actor", | ||
| "account_id": "712020:07290b97-3f2b-4fe2-81a5-d5d501f306fe", | ||
| "display_name": "Edge JiraBot" | ||
| }, | ||
| { | ||
| "type": "atlassian-user-role-actor", | ||
| "account_id": "712020:510de16d-fc42-48cf-8412-8b5cb72dc6bd", | ||
| "display_name": "Jira-SD-Elements-Integration Bot" | ||
| }, | ||
| { | ||
| "type": "atlassian-group-role-actor", | ||
| "group_id": "70b1c436-6bfe-4027-bc2d-78ec147d8cb1", | ||
| "group_name": "OpenShift Jira Bots" | ||
| }, | ||
| { | ||
| "type": "atlassian-group-role-actor", | ||
| "group_id": "13bd0387-d75c-4c18-9d37-5439e8bf984c", | ||
| "group_name": "Red Hat Employee" | ||
| } | ||
| ] | ||
| }, | ||
| { | ||
| "id": "10127", | ||
| "name": "Scrum master", | ||
| "description": "This role is intended for users that assist with day-to-day operation of the team but don't require full project administration access. Scrum masters, program managers, and others may find themselves in this role. It provides access to create, edit, start, and end sprints.", | ||
| "actors": [ | ||
| { | ||
| "type": "atlassian-user-role-actor", | ||
| "account_id": "712020:eca54813-6101-4bb6-b169-5b91a02029a1", | ||
| "display_name": "Jeff Roche" | ||
| }, | ||
| { | ||
| "type": "atlassian-group-role-actor", | ||
| "group_id": "4937a28d-eae0-4776-990c-589b162a7fe7", | ||
| "group_name": "openshift-scrummaster-role" | ||
| } | ||
| ] | ||
| }, | ||
| { | ||
| "id": "10128", | ||
| "name": "Approver", | ||
| "description": "Approval permissions", | ||
| "actors": [] | ||
| }, | ||
| { | ||
| "id": "10129", | ||
| "name": "Viewers", | ||
| "description": "Read-only access", | ||
| "actors": [] | ||
| }, | ||
| { | ||
| "id": "10162", | ||
| "name": "Version Manager", | ||
| "description": "Manages versions and releases", | ||
| "actors": [] | ||
| }, | ||
| { | ||
| "id": "10056", | ||
| "name": "Service Desk Customers", | ||
| "description": "Service desk customer access", | ||
| "actors": [] | ||
| }, | ||
| { | ||
| "id": "10057", | ||
| "name": "Service Desk Team", | ||
| "description": "Service desk team members", | ||
| "actors": [] | ||
| }, | ||
| { | ||
| "id": "10003", | ||
| "name": "atlassian-addons-project-access", | ||
| "description": "Atlassian add-on access", | ||
| "actors": [] | ||
| } | ||
| ] |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify whether Jira API supports role actor management
echo "Checking Jira API documentation for project role endpoints..."
# Check if there are alternative endpoints for managing role actors
rg -n "role" edge-scrum/.ci/scripts/sync-projects.sh -A 5 -B 5Repository: openshift-eng/edge-tooling
Length of output: 551
🏁 Script executed:
# Get more context around the role handling in the sync script
sed -n '200,240p' edge-scrum/.ci/scripts/sync-projects.shRepository: openshift-eng/edge-tooling
Length of output: 1170
🏁 Script executed:
# Check if there are other references to roles in the sync script
rg -n "role" edge-scrum/.ci/scripts/sync-projects.shRepository: openshift-eng/edge-tooling
Length of output: 96
🏁 Script executed:
# Check for documentation in README or related files about role management
find . -name "README*" -o -name "*.md" | head -20 | xargs grep -l "role" 2>/dev/nullRepository: openshift-eng/edge-tooling
Length of output: 190
🏁 Script executed:
# Check the full structure of the sync script to see what functions are called for project updates
rg -n "update_project|sync" edge-scrum/.ci/scripts/sync-projects.sh | head -20Repository: openshift-eng/edge-tooling
Length of output: 299
🏁 Script executed:
# Get the update_project function implementation
sed -n '111,160p' edge-scrum/.ci/scripts/sync-projects.shRepository: openshift-eng/edge-tooling
Length of output: 1595
🏁 Script executed:
# Read the README in .jira-config directory
cat edge-scrum/.jira-config/README.mdRepository: openshift-eng/edge-tooling
Length of output: 6339
🏁 Script executed:
# Check what fields are actually extracted from projects.json
rg -n "jq" edge-scrum/.ci/scripts/sync-projects.sh | head -20Repository: openshift-eng/edge-tooling
Length of output: 640
Roles are not synced; document or remove the unused configuration.
Role assignments in projects.json (lines 14-153) are not applied during sync operations. The sync script explicitly acknowledges this limitation (sync-projects.sh lines 219-223) because the Jira REST API does not support role actor updates via the project endpoint. The update_project() function only syncs name, description, leadAccountId, and assigneeType—roles are never extracted or processed.
While the README.md already documents that roles are "UI-Only Configuration," having 140 lines of unused role configuration in projects.json creates:
- Configuration drift risk: Roles can change in the Jira UI without the JSON reflecting those changes
- Misleading maintenance burden: The presence of roles in the config file suggests they are managed by this sync process when they are not
- Developer confusion: New team members may assume roles are synced and waste time troubleshooting
Either:
- Remove the roles field from projects.json and consolidate all role documentation in a separate manual setup guide in the README
- Add an inline comment within projects.json clarifying that roles are for reference only and must be managed via the Jira UI
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@edge-scrum/.jira-config/projects.json` around lines 14 - 153, projects.json
contains a large "roles" block that is not synced by the tooling
(sync-projects.sh acknowledges this and update_project() only syncs
name/description/leadAccountId/assigneeType), causing configuration drift and
confusion; either remove the entire "roles" field from projects.json and move
role setup instructions into README.md, or add a prominent inline comment above
the "roles" array in projects.json stating "UI-only — not managed by
sync-projects.sh / update_project()" and document the manual Jira UI steps in
README.md (ensure README.md cross-references sync-projects.sh and
update_project()).
|
Holding so I can address the coderabbit feedback (pretty much all valid points) and wait for agreement on Edge KR 1.1 - Unified Scrum |
|
@jeff-roche: The following tests 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. |
Summary
edge-scrum/.jira-config/as the source of truth for OCPEDGE Jira metadata (boards, filters, projects, components, labels)edge-scrum/.ci/scripts/with sync scripts that apply config changes to Jira via REST APIedge-scrum/.ci/schemas/with JSON Schema definitions for all config filesWorkflows
PR (
jira-sync-pr.yml) — triggers on.jira-config/**changes:validate-configs— validates JSON against schemas, checks for duplicate IDs/namesvalidate-readme— enforces that.jira-config/README.mdis updated alongside config changesdry-run— previews what would be synced to Jira without making API callsPost-merge (
jira-sync-apply.yml) — triggers on push tomainorworkflow_dispatch:validate-configsbefore applying (defense in depth)workflow_dispatchtriggers a full syncSecurity
.envfiles committedJIRA_URLdefaults tohttps://redhat.atlassian.net; onlyJIRA_USERNAMEandJIRA_API_TOKENneed to be set as repo secretsAuthorization: Basicheader (token not exposed in process table)mktemp -dwithtrapcleanupTest plan
JIRA_USERNAMEandJIRA_API_TOKENrepo secrets in GitHubvalidate-configsjob passes on this PRvalidate-readmejob passes on this PRdry-runjob passes and outputs expected changesapplyjob runs and syncs configs to Jira🤖 Generated with Claude Code