From e4eb098c9cbc0c0512c58d9f370c68d640b40ef9 Mon Sep 17 00:00:00 2001 From: agentman3334 Date: Sat, 18 Jul 2026 11:41:32 +0300 Subject: [PATCH 1/2] refactor(sdlc-pipeline): enforce PR-based docs flow, fix auth/security issues, add sprint scripts - Replace direct-push docs/reports with docs branch + PR to dev (GitHub branch protection applies to whole branch, not paths) - Fix Jira API auth: require Atlassian gateway URL + MCP Authorization header from mcp_settings.json (direct site URL always returns 401) - Fix Windows PowerShell: use .ps1 script files instead of inline commands (Bash tool strips $ from inline PowerShell) - Add sprint-start/sprint-close template scripts (ps1/sh) - Fix git clone: use credential helper, never embed PAT in URL - Fix merge conflict resolution: domain-owner based instead of blanket prefer-dev (main may contain production hotfixes) - Move JFrog non-secret config to GitHub Actions variables - Add deployment rollback using captured previous image - Persist user-selected integration branch across all downstream agents - PM Agent no longer creates/merges PRs (developer agents handle) --- skills/sdlc-agentic-pipeline/SKILL.md | 48 ++++--- .../references/agents/backend-agent.md | 38 +++--- .../references/agents/code-reviewer-agent.md | 4 +- .../references/agents/devops-agent.md | 62 ++++++--- .../references/agents/frontend-agent.md | 28 ++-- .../references/agents/pm-agent.md | 128 +++++++----------- .../references/pipeline.md | 61 +++++---- .../references/setup/service-onboarding.md | 73 +++++----- .../references/templates/add_ssh_key.py | 20 ++- .../references/templates/ci-cd.yml | 11 +- .../references/templates/env-template.env | 2 + .../references/templates/mcp-settings.json | 2 +- .../references/templates/set-secrets.js | 10 +- .../templates/sprint-scripts/README.md | 35 +++++ .../templates/sprint-scripts/sprint-close.ps1 | 75 ++++++++++ .../templates/sprint-scripts/sprint-close.sh | 68 ++++++++++ .../templates/sprint-scripts/sprint-start.ps1 | 80 +++++++++++ .../templates/sprint-scripts/sprint-start.sh | 72 ++++++++++ 18 files changed, 603 insertions(+), 214 deletions(-) create mode 100644 skills/sdlc-agentic-pipeline/references/templates/sprint-scripts/README.md create mode 100644 skills/sdlc-agentic-pipeline/references/templates/sprint-scripts/sprint-close.ps1 create mode 100644 skills/sdlc-agentic-pipeline/references/templates/sprint-scripts/sprint-close.sh create mode 100644 skills/sdlc-agentic-pipeline/references/templates/sprint-scripts/sprint-start.ps1 create mode 100644 skills/sdlc-agentic-pipeline/references/templates/sprint-scripts/sprint-start.sh diff --git a/skills/sdlc-agentic-pipeline/SKILL.md b/skills/sdlc-agentic-pipeline/SKILL.md index 581cbe0..123d080 100644 --- a/skills/sdlc-agentic-pipeline/SKILL.md +++ b/skills/sdlc-agentic-pipeline/SKILL.md @@ -154,14 +154,14 @@ See `references/templates/mcp-settings.json` for the template. | 0 PM + Frontend/Backend/DevOps Onboarding: auto-provision agents, Opt A (existing repo, PM read-only) or Opt B (new repo, parallel Backend+Frontend build, DevOps configs) | | 1 PM Requirement breakdown, PRD, batch Jira task creation (hyperlinks to user) | | 1b Frontend/Backend Requirement review (PARALLEL via Jira async dispatch) | -| 2 PM Sprint start (Jira Agile API) + SDD setup (direct push, no PR) | +| 2 PM + Developer Sprint start (Jira Agile API) + SDD setup (developer agent: docs branch + PR to dev) | | 3 Frontend/Backend Code dev (PARALLEL via Jira async), Semgrep pre-scan, branching, PR, tests | | 4 Code Reviewer PR review (batch), secret scanning (batch), GitHub approval | | 5 Tester + PM + Dev E2E testing + auto-merge feature PRs (5b merged into 5) + CI/CD auto-triggers | | 6 DevOps CI/CD (auto-triggered, cached) + JFrog verify + SonarCloud QG (combined) | | 7 PM+Developer Release review (PM: sign-offs+approval) + merge (Developer: PR create+merge, simplified conflict resolution) | | 8 PM+DevOps Deploy auth (PM: human approval) + execution (DevOps: SSH+docker pull+run) | -| 9 PM+Developer Sprint close, retro, HTML report, direct push to GitHub (no PR) | +| 9 PM+Developer Sprint close, retro, HTML report, docs branch + PR to GitHub | +---------------------------------------------------------------------------+ ``` @@ -171,7 +171,8 @@ See `references/templates/mcp-settings.json` for the template. (Steps 0, 1b, 3). PM dispatches via Jira comments, both agents pick up independently. 2. **Batch Jira operations**: Bulk create API for tasks (Step 1), batch transitions. 3. **Direct push for docs/reports**: `.opencode/**`, `docs/**`, `reports/**` paths - exempt from PR requirement via GitHub path-based branch protection (Steps 2, 9). + use a docs branch + PR targeting `dev` (GitHub branch protection applies to the whole + branch, not individual paths, so a PR is required even for documentation changes). 4. **Auto-trigger CI/CD**: `on: push` to `dev` branch. No manual DevOps trigger (Step 5->6). 5. **Cached builds**: pip, node_modules, Docker layers cached in GitHub Actions (Step 6). 6. **Combined CI/CD + verification**: JFrog artifact check + SonarCloud QG @@ -361,7 +362,7 @@ summarizing the entire process, operations, and actions taken during the flow. - GitHub: `https://github.com/{GITHUB_OWNER}/{GITHUB_REPO}` - PRs: `https://github.com/{GITHUB_OWNER}/{GITHUB_REPO}/pull/{PR_NUMBER}` - SonarCloud: `https://sonarcloud.io/project/overview?id={SONAR_PROJECT_KEY}` - - JFrog: `https://{JFROG_PLATFORM_URL}/ui/repos/tree/General/{JFROG_REPO_KEY}` + - JFrog: `{JFROG_PLATFORM_URL}/ui/repos/tree/General/{JFROG_REPO_KEY}` - GitHub Actions: `https://github.com/{GITHUB_OWNER}/{GITHUB_REPO}/actions` - Contents (single-page scrollable report): - Header: project name (linked to GitHub repo), sprint name, date range, overall status badge @@ -483,7 +484,7 @@ main (production-ready - only released code, deploy from here) └── docs/sdd- ``` -- **`main`**: Production branch. Only updated via `dev` → `main` merge at release time (Step 8). +- **`main`**: Production branch. Only updated via `dev` → `main` merge at release time (Step 7). Branch protection rules MUST be enabled (no direct pushes). - **`dev`**: Integration branch. All feature, fix, and docs PRs target `dev` as base. Multiple feature branches merge here for integration testing before release. @@ -491,16 +492,17 @@ main (production-ready - only released code, deploy from here) > **Option A (Existing Repo):** The user's existing branch strategy takes precedence. > During onboarding (Step 0.A.6), the PM Agent asks the user which branch strategy to -> use (existing `develop`, GitFlow `dev`, trunk-based, or custom). Branches are only -> created by developer agents, never by the PM Agent. The pipeline adapts to the -> user's chosen strategy for all PR targets. +> use (existing `develop`, GitFlow `dev`, trunk-based, or custom). The selected branch +> is persisted and passed to all downstream agents (Backend, Frontend, DevOps) for +> CI/CD triggers, feature merges, and release PRs. Branches are only created by +> developer agents, never by the PM Agent. ### Release Merge: `dev` → `main` At Step 7 (Release Review), after all feature PRs are merged into `dev` and all gates pass, the PM Agent authorizes and the developer agent (Backend if both active, otherwise sole developer) creates and merges `dev` into `main` via GitHub MCP. -This is the only way code reaches `main`. Deployment (Step 9) always pulls from `main`. +This is the only way code reaches `main`. Deployment (Step 8) always pulls from `main`. ## Branch Naming Convention @@ -594,9 +596,14 @@ The pipeline requires explicit human approval at these points: > crashes. Requires Project Administrator permissions. > 2. **Jira direct REST API 401**: Direct calls to `{site}.atlassian.net` with > Basic auth return 401. Must use the Atlassian API gateway -> (`api.atlassian.com/ex/jira/{cloudUuid}/rest/...`). Discover the cloud UUID -> by calling `atlassian-rovo-mcp_getVisibleJiraProjects` and extracting it -> from the `self` URL in the response. +> (`api.atlassian.com/ex/jira/{cloudUuid}/rest/...`) with the `Authorization` +> header from `.codeartsdoer/mcp/mcp_settings.json` +> (`mcpServers["atlassian-rovo-mcp"].headers.Authorization`). Any other auth +> token will fail. Discover the cloud UUID by calling +> `atlassian-rovo-mcp_getVisibleJiraProjects` and extracting it from the `self` +> URL in the response. On Windows, the CodeArts Bash tool strips `$` from +> inline PowerShell — always write a `.ps1` script file first, then execute +> with `powershell -NoProfile -ExecutionPolicy Bypass -File`. > 3. **Jira sprint name length**: Must be shorter than 30 characters or the API > returns 400. > 4. **Sprint field value type**: `customfield_10020` (Sprint) must be a number, @@ -607,6 +614,13 @@ The pipeline requires explicit human approval at these points: > NOT support partial updates. Sending only `{"state": "closed"}` returns 400. > Must `GET /sprint/{id}` first to fetch existing `name` and `startDate`, then > `PUT` with complete body: `{state, name, startDate, endDate, goal}`. +> 6b. **Sprint close must use gateway URL + MCP auth**: Direct site URL +> (`{site}.atlassian.net`) always returns 401. Must use the Atlassian API gateway +> (`https://api.atlassian.com/ex/jira/{cloudUuid}/rest/agile/1.0`) with the +> `Authorization` header from `.codeartsdoer/mcp/mcp_settings.json` +> (`mcpServers["atlassian-rovo-mcp"].headers.Authorization`). On Windows, the +> CodeArts Bash tool strips `$` from inline PowerShell — always write a `.ps1` +> script file first, then execute with `powershell -File`. > 7. **JFrog Docker repository naming**: Do NOT use underscores in repository names > (DNS limitation). Use hyphens (e.g., `docker-dev-local` not `docker_dev_local`). > 8. **JFrog build API requires project param**: `GET /artifactory/api/build/{name}` @@ -677,9 +691,9 @@ Ready-to-fill templates are in `references/templates/`: analysis. Use Semgrep MCP for local scanning. - CI/CD is **auto-triggered** on push to `dev` (not manual). This ensures only reviewed, tested code enters the pipeline immediately after merge. -- All SDD documents (`spec.md`, `design.md`, `tasks.md`) are pushed DIRECTLY to GitHub - (no PR needed - `.opencode/**` exempt via path-based branch protection). Developer agent - pushes directly to `dev`. +- All SDD documents (`spec.md`, `design.md`, `tasks.md`) are pushed to GitHub + via a developer agent on a docs branch + PR targeting `dev` (GitHub branch protection + applies to the whole branch, so a PR is required). - **Step 5 (E2E + Auto-Merge):** Tester runs E2E, then PM verifies gates + asks human approval, developer agent merges feature PRs into `dev`. CI/CD auto-triggers on dev push (no separate Step 5b or manual CI/CD trigger). @@ -695,8 +709,8 @@ Ready-to-fill templates are in `references/templates/`: executes (SSH into Huawei Cloud ECS, docker pull, docker run, health check, rollback on failure). - **Step 9 (Report Push):** PM Agent generates HTML report, developer agent - (Backend if both active, otherwise sole developer) pushes DIRECTLY to `dev` - (no PR - `reports/**` exempt via path-based branch protection). + (Backend if both active, otherwise sole developer) creates a docs branch + PR + targeting `dev` and merges it (GitHub branch protection applies to the whole branch). ## Sharing This Skill diff --git a/skills/sdlc-agentic-pipeline/references/agents/backend-agent.md b/skills/sdlc-agentic-pipeline/references/agents/backend-agent.md index 67de6a2..40132dd 100644 --- a/skills/sdlc-agentic-pipeline/references/agents/backend-agent.md +++ b/skills/sdlc-agentic-pipeline/references/agents/backend-agent.md @@ -118,10 +118,11 @@ When the Backend Agent is the primary PR operator, it handles: ``` - If the MCP returns a **422** or "already exists" error, report back to the PM Agent who will ask the user for a different name and retry. -- **Clone the newly created repo** to the local working directory: +- **Clone the newly created repo** to the local working directory (use credential helper — never embed PAT in URL): ```bash - git clone "https://@github.com//.git" + git clone "https://github.com//.git" ``` + The GitHub MCP Bearer token is used for authentication via the configured credential helper. Do NOT pass the PAT as a URL parameter — it would be exposed in command history, process arguments, and tool logs. - Analyze the backend requirements to identify modules, API endpoints, and data models - Create the complete backend directory structure: - `backend/app/` - main application code @@ -369,16 +370,11 @@ Before merging any feature PR, verify ALL of the following: ### 7.3 Merge Conflict Resolution (Simplified) -If the `dev` -> `main` merge encounters conflicts (simplified - default `prefer dev`): +If the `dev` -> `main` merge encounters conflicts: 1. **Create resolution branch**: `git checkout -b fix/backend/resolve-release-conflict dev` 2. **Merge main into resolution branch**: `git merge main` (conflicts appear) -3. **Accept dev version for ALL conflicts** (dev has latest tested code) -4. **Commit and push resolution** -5. **Run CI/CD on resolution branch** (delegate to DevOps Agent for trigger) -6. **If CI/CD passes** -> create PR to `main` and merge (DONE - 4 steps, not 18) -7. **If CI/CD fails** -> THEN do full domain-owner conflict resolution: - - Classify conflicting files by ownership: +3. **Resolve each conflict by domain ownership** (do NOT blanket-accept dev for all files — main may contain production hotfixes not in dev): - `backend/**` -> Backend Agent resolves - `frontend/**` -> Delegate to Frontend Agent via Jira comment - `docker-compose.yml`, `**/Dockerfile`, `.github/workflows/**` -> Delegate to DevOps Agent via Jira comment @@ -416,18 +412,18 @@ If the `dev` -> `main` merge encounters conflicts (simplified - default `prefer git commit -m "docs: add SDLC process report" git push origin docs/sdlc-reports ``` -4. DIRECT PUSH to `dev` (no PR - `reports/**` exempt via path-based branch protection): - ``` - github_create_pull_request( - owner="", - repo="", - title="docs: SDLC process report", - head="docs/sdlc-reports", - base="dev" - ) - ``` -5. Report commit URL to PM Agent -6. Report PR link to PM Agent: `@agent:pm Report PR created and merged: ` + 4. Create PR to `dev` and merge it: + ``` + github_create_pull_request( + owner="", + repo="", + title="docs: SDLC process report", + head="docs/sdlc-reports", + base="dev" + ) + ``` + 5. After PR is created, merge it via `github_merge_pull_request` + 6. Report commit URL and merged PR link to PM Agent: `@agent:pm Report published and merged: ` --- diff --git a/skills/sdlc-agentic-pipeline/references/agents/code-reviewer-agent.md b/skills/sdlc-agentic-pipeline/references/agents/code-reviewer-agent.md index 52130cb..d9219ea 100644 --- a/skills/sdlc-agentic-pipeline/references/agents/code-reviewer-agent.md +++ b/skills/sdlc-agentic-pipeline/references/agents/code-reviewer-agent.md @@ -47,7 +47,9 @@ avatar: avatar1 > on throwback. > > **Branch strategy:** All PRs target `dev` as the base branch (not `main`). -> The `dev` → `main` merge happens later at Step 7 (Release Review) by the PM Agent. +> The `dev` → `main` merge happens later at Step 7 (Release Review) and is +> performed by the developer agent (Backend if both active, otherwise sole developer). +> The PM Agent does NOT create or merge PRs. ### 4.1 Task Discovery - Discover review tasks via JQL: `labels = agent:code-reviewer AND status = "In Review"` diff --git a/skills/sdlc-agentic-pipeline/references/agents/devops-agent.md b/skills/sdlc-agentic-pipeline/references/agents/devops-agent.md index 277ea88..f4a287b 100644 --- a/skills/sdlc-agentic-pipeline/references/agents/devops-agent.md +++ b/skills/sdlc-agentic-pipeline/references/agents/devops-agent.md @@ -110,9 +110,10 @@ PR operations delegated to developer agents: > the DevOps Agent handles this during Step 3 via a feature branch and PR. ### 0.1 Context -- The PM Agent has created the GitHub repository (Step 0.1.B.3) and cloned it locally +- The Backend Agent has created the GitHub repository and cloned it locally - The Backend Agent has already built and pushed backend code to `dev` - The Frontend Agent has already built and pushed frontend code to `dev` +- The DevOps Agent clones the repository before infrastructure work - The PM Agent invokes the DevOps Agent via the Task tool with: - The project structure (backend + frontend directories) - The tech stack for each service (e.g., Python/FastAPI backend, vanilla HTML/CSS/JS frontend) @@ -174,10 +175,11 @@ PR operations delegated to developer agents: - The DevOps Agent transitions the task to "In Progress" ### What to Do -1. **Clone the repo locally** (the DevOps Agent owns this git operation): +1. **Clone the repo locally** (the DevOps Agent owns this git operation — use credential helper, never embed PAT in URL): ```bash - git clone "https://@github.com//.git" + git clone "https://github.com//.git" ``` + The GitHub MCP Bearer token is used for authentication via the configured credential helper. Do NOT pass the PAT as a URL parameter — it would be exposed in command history, process arguments, and tool logs. 2. **Create a feature branch** from the user's chosen integration branch: ```bash git checkout -b feature/devops/ @@ -241,10 +243,10 @@ PR operations delegated to developer agents: ``` - If workflow needs updates, edit via `github_create_or_update_file` -### 6.4 GitHub Action Secrets Checklist (Required Before First Run) +### 6.4 GitHub Action Secrets & Variables Checklist (Required Before First Run) Before triggering the CI/CD workflow for the first time, the DevOps Agent MUST -ensure all required GitHub Action secrets are configured. The `ci-cd.yml` template +ensure all required GitHub Action secrets and variables are configured. The `ci-cd.yml` template documents these in its header comment. Required secrets (add under **Settings -> Secrets and variables -> Actions -> New repository secret**): @@ -252,20 +254,27 @@ Required secrets (add under **Settings -> Secrets and variables -> Actions -> Ne | Secret | Purpose | |--------|---------| | `SONAR_TOKEN` | SonarCloud authentication token | -| `JFROG_PLATFORM_URL` | JFrog platform base URL (e.g. `https://.jfrog.io`) | -| `JFROG_DOCKER_REGISTRY` | JFrog Docker registry hostname | -| `JFROG_USERNAME` | JFrog user account | | `JFROG_PASSWORD` | JFrog password / access token | -| `JFROG_PROJECT` | JFrog project key | > `GITHUB_TOKEN` is auto-provided by GitHub Actions - do NOT ask the user to add it. +Required variables (add under **Settings -> Secrets and variables -> Actions -> Variables tab**): + +| Variable | Purpose | +|----------|---------| +| `JFROG_PLATFORM_URL` | JFrog platform base URL including scheme (e.g. `https://.jfrog.io`) | +| `JFROG_DOCKER_REGISTRY` | JFrog Docker registry hostname (no scheme) | +| `JFROG_USERNAME` | JFrog user account (email address) | +| `JFROG_PROJECT` | JFrog project key | +| `SONAR_PROJECT_KEY` | SonarCloud project key | + Procedure: 1. List existing secrets via GitHub API: `GET /repos/{owner}/{repo}/actions/secrets`. -2. Compare against the 6 required secrets above. -3. If ANY required secret is missing, use the `question` tool to ask the user to add - the missing secret(s) before proceeding. Do not continue until the user confirms. -4. Only after all secrets are present, proceed to monitor the auto-triggered pipeline (6.2). +2. List existing variables via GitHub API: `GET /repos/{owner}/{repo}/actions/variables`. +3. Compare against the 2 required secrets and 5 required variables above. +4. If ANY required secret or variable is missing, use the `question` tool to ask the user to add + the missing value(s) before proceeding. Do not continue until the user confirms. +5. Only after all secrets and variables are present, proceed to monitor the auto-triggered pipeline (6.2). ### 6.5 Manual CI/CD Trigger - **Option A - GitHub API via REST** (recommended, works without `gh` CLI): @@ -487,11 +496,14 @@ Procedure: $sshKey = "$env:USERPROFILE\.ssh\id_rsa" $ecsHost = "" $ecsUser = "" - $image = "//:latest" - $containerName = "sdlc-pipeline-guideline" + $image = "//:" + $containerName = "sdlc-pipeline-guideline" - # Pull latest image - ssh -i $sshKey $ecsUser@$ecsHost "docker pull $image" + # Capture currently running image for rollback + $previousImage = ssh -i $sshKey $ecsUser@$ecsHost "docker inspect --format='{{.Config.Image}}' $containerName 2>`$null" + + # Pull release image + ssh -i $sshKey $ecsUser@$ecsHost "docker pull $image" # Stop and remove existing container (if any) ssh -i $sshKey $ecsUser@$ecsHost "docker stop $containerName 2>/dev/null; docker rm $containerName 2>/dev/null" @@ -505,10 +517,13 @@ Procedure: sshKey="$HOME/.ssh/id_rsa" ecsHost="" ecsUser="" - image="//:latest" + image="//:" containerName="sdlc-pipeline-guideline" - # Pull latest image + # Capture currently running image for rollback + previousImage=$(ssh -i "$sshKey" "$ecsUser@$ecsHost" "docker inspect --format='{{.Config.Image}}' $containerName 2>/dev/null" || echo "") + + # Pull release image ssh -i "$sshKey" "$ecsUser@$ecsHost" "docker pull $image" # Stop and remove existing container (if any) @@ -540,10 +555,13 @@ Procedure: ``` ### 9.3 Rollback on Failure -- If deployment fails: rollback via `docker stop` + `docker run` previous image tag +- If deployment fails: rollback using the captured previous image: + ```bash + ssh -i "$sshKey" "$ecsUser@$ecsHost" "docker stop $containerName; docker rm $containerName; docker run -d --name $containerName -p 80:80 $previousImage" + ``` - Report success or failure to PM Agent via Jira comment: - - Success: `@agent:pm Deployment to Huawei Cloud ECS complete - version live at http://` - - Failure: `@agent:pm Deployment to Huawei Cloud ECS FAILED - rollback executed` + - Success: `@agent:pm Deployment to Huawei Cloud ECS complete - version live at http://` + - Failure: `@agent:pm Deployment to Huawei Cloud ECS FAILED - rollback executed to previous image` --- diff --git a/skills/sdlc-agentic-pipeline/references/agents/frontend-agent.md b/skills/sdlc-agentic-pipeline/references/agents/frontend-agent.md index 6dcd6a7..f25c85a 100644 --- a/skills/sdlc-agentic-pipeline/references/agents/frontend-agent.md +++ b/skills/sdlc-agentic-pipeline/references/agents/frontend-agent.md @@ -95,12 +95,12 @@ When the Frontend Agent is the primary PR operator, it handles: > the frontend code already exists and the Frontend Agent starts at Step 1. ### 0.1 Context -- The PM Agent has created the GitHub repository (Step 0.1.B.3) and cloned it locally +- The Backend Agent has created the GitHub repository (Step 0.1.B.3) and cloned it locally - The PM Agent has parsed the user's Project Prompt and extracted the frontend scope - The PM Agent invokes the Frontend Agent via the Task tool with: - The frontend requirements extracted from the Project Prompt - The tech stack to use (e.g., vanilla HTML/CSS/JS) - - The path to the cloned repo's `frontend/` directory + - The repository URL/path (the Frontend Agent clones or uses an explicitly provided workspace) ### 0.2 Build Frontend Codebase - Analyze the frontend requirements to identify pages, components, and UI features @@ -341,18 +341,18 @@ If the `dev` -> `main` merge encounters conflicts: git commit -m "docs: add SDLC process report" git push origin docs/sdlc-reports ``` -4. DIRECT PUSH to `dev` (no PR - `reports/**` exempt via path-based branch protection): - ``` - github_create_pull_request( - owner="", - repo="", - title="docs: SDLC process report", - head="docs/sdlc-reports", - base="dev" - ) - ``` -5. Report commit URL to PM Agent -6. Report PR link to PM Agent: `@agent:pm Report PR created and merged: ` + 4. Create PR to `dev` and merge it: + ``` + github_create_pull_request( + owner="", + repo="", + title="docs: SDLC process report", + head="docs/sdlc-reports", + base="dev" + ) + ``` + 5. After PR is created, merge it via `github_merge_pull_request` + 6. Report commit URL and merged PR link to PM Agent: `@agent:pm Report published and merged: ` --- diff --git a/skills/sdlc-agentic-pipeline/references/agents/pm-agent.md b/skills/sdlc-agentic-pipeline/references/agents/pm-agent.md index 77f94fb..2022b31 100644 --- a/skills/sdlc-agentic-pipeline/references/agents/pm-agent.md +++ b/skills/sdlc-agentic-pipeline/references/agents/pm-agent.md @@ -91,7 +91,7 @@ that can authorize deployment and close sprints. During Step 0 onboarding with an existing repo, the PM Agent additionally: - Inventories existing artifacts (Dockerfiles, docker-compose.yml, ci-cd.yml, etc.) - Asks the user about their development intent (new features, bug fixes, etc.) -- Asks the user about their preferred branch strategy +- Asks the user about their preferred branch strategy and **persists the selected integration/release branch** — this branch is passed to every downstream agent (Backend, Frontend, DevOps) and used for CI/CD triggers, feature merges, and release PRs instead of hard-coding `dev` - Existing artifacts are NEVER modified without explicit user approval - Branches are NEVER created/deleted/renamed without explicit user approval @@ -222,8 +222,10 @@ $baseUrl = "https://api.atlassian.com/ex/jira/${cloudUuid}/rest/agile/1.0" **macOS/Linux (Bash):** ```bash -# Step 1: Read .env for project context -set -a; source "/.env"; set +a +# Step 1: Read .env for project context (safe parsing — never source/eval .env) +while IFS='=' read -r key value; do + case "$key" in JIRA_*) export "$key=$value" ;; esac +done < "/.env" # Step 2: Read MCP auth header from mcp_settings.json authHeader=$(jq -r '.mcpServers["atlassian-rovo-mcp"].headers.Authorization' "/.codeartsdoer/mcp/mcp_settings.json") @@ -285,27 +287,19 @@ atlassian-rovo-mcp_editJiraIssue(cloudId, issueIdOrKey, fields: { "customfield_1 **Step 2.2.5 - Start Sprint (full PUT):** -**Windows (PowerShell):** -```powershell -$startDate = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ss.fffZ") -$endDate = (Get-Date).AddDays(14).ToString("yyyy-MM-ddTHH:mm:ss.fffZ") -$body = @{ state = "active"; name = ""; startDate = $startDate; endDate = $endDate; goal = "" } | ConvertTo-Json -$uri = "${baseUrl}/sprint/${sprintId}"; $response = Invoke-RestMethod -Uri $uri -Method Put -Headers $headers -Body $body -# Verify $response.state == "active" -# Note: Sprint must be in "future" state before it can be started -``` +> **Windows:** The CodeArts Bash tool strips `$` from inline PowerShell commands. +> Use the cross-platform template scripts from `references/templates/sprint-scripts/`: +> - Copy `sprint-start.ps1` (or `sprint-start.sh` on macOS/Linux) to the project root +> - Replace all `` values with actual values +> - Execute: `powershell -NoProfile -ExecutionPolicy Bypass -File "sprint-start.ps1"` +> - **Delete the script file after execution** (it contains auth tokens) -**macOS/Linux (Bash):** -```bash -startDate=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z") -# macOS uses -v+14d, Linux uses -d "+14 days" -endDate=$(date -u -v+14d +"%Y-%m-%dT%H:%M:%S.000Z" 2>/dev/null || date -u -d "+14 days" +"%Y-%m-%dT%H:%M:%S.000Z") -body=$(jq -n --arg state "active" --arg name "" --arg startDate "$startDate" --arg endDate "$endDate" --arg goal "" \ - '{state: $state, name: $name, startDate: $startDate, endDate: $endDate, goal: $goal}') -response=$(curl -s -X PUT -H "Authorization: $authHeader" -H "Content-Type: application/json" -d "$body" "${baseUrl}/sprint/${sprintId}") -# Verify: echo "$response" | jq -r '.state' -# Note: Sprint must be in "future" state before it can be started -``` +Template scripts are available at `references/templates/sprint-scripts/`: + +| Script | Platform | Usage | +|--------|----------|-------| +| `sprint-start.ps1` | Windows | `powershell -NoProfile -ExecutionPolicy Bypass -File "sprint-start.ps1"` | +| `sprint-start.sh` | macOS/Linux | `chmod +x sprint-start.sh && ./sprint-start.sh` | **Step 2.2.6 - Partially Update Sprint (POST):** @@ -330,32 +324,24 @@ response=$(curl -s -X POST -H "Authorization: $authHeader" -H "Content-Type: app > You must first `GET /sprint/{id}` to fetch existing `name` and `startDate`, > then `PUT` with the complete body including all required fields. -**Windows (PowerShell):** -```powershell -# Step 1: GET sprint to fetch existing fields -$uri = "${baseUrl}/sprint/${sprintId}"; $sprint = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers - -# Step 2: PUT with complete body (state + name + startDate + endDate) -$endDate = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ss.fffZ") -$body = @{ state = "closed"; name = $sprint.name; startDate = $sprint.startDate; endDate = $endDate; goal = $sprint.goal } | ConvertTo-Json -$response = Invoke-RestMethod -Uri $uri -Method Put -Headers $headers -Body $body -# Sprint must be in "active" state before it can be closed -# Verify $response.state == "closed" -``` +> **CRITICAL — Auth & URL:** Direct site URL (`{site}.atlassian.net`) always returns 401. +> You MUST use the Atlassian API gateway URL (`https://api.atlassian.com/ex/jira/{cloudUuid}/rest/agile/1.0`) +> with the `Authorization` header from `.codeartsdoer/mcp/mcp_settings.json` +> (`mcpServers["atlassian-rovo-mcp"].headers.Authorization`). Any other auth token will fail. -**macOS/Linux (Bash):** -```bash -# Step 1: GET sprint to fetch existing fields -sprint=$(curl -s -H "Authorization: $authHeader" "${baseUrl}/sprint/${sprintId}") - -# Step 2: PUT with complete body (state + name + startDate + endDate) -endDate=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z") -body=$(echo "$sprint" | jq --arg state "closed" --arg endDate "$endDate" \ - '{state: $state, name: .name, startDate: .startDate, endDate: $endDate, goal: .goal}') -response=$(curl -s -X PUT -H "Authorization: $authHeader" -H "Content-Type: application/json" -d "$body" "${baseUrl}/sprint/${sprintId}") -# Sprint must be in "active" state before it can be closed -# Verify: echo "$response" | jq -r '.state' -``` +> **Windows:** The CodeArts Bash tool strips `$` from inline PowerShell commands. +> Use the cross-platform template scripts from `references/templates/sprint-scripts/`: +> - Copy `sprint-close.ps1` (or `sprint-close.sh` on macOS/Linux) to the project root +> - Replace all `` values with actual values +> - Execute: `powershell -NoProfile -ExecutionPolicy Bypass -File "sprint-close.ps1"` +> - **Delete the script file after execution** (it contains auth tokens) + +Template scripts are available at `references/templates/sprint-scripts/`: + +| Script | Platform | Usage | +|--------|----------|-------| +| `sprint-close.ps1` | Windows | `powershell -NoProfile -ExecutionPolicy Bypass -File "sprint-close.ps1"` | +| `sprint-close.sh` | macOS/Linux | `chmod +x sprint-close.sh && ./sprint-close.sh` | ### 2.3 SDD Setup - After sprint is active, proceed with Spec-Driven Development setup @@ -386,7 +372,8 @@ Full Jira Software Agile REST API endpoint reference (base: `/rest/agile/1.0`): **Sprint States:** `future` -> `active` -> `closed` **Common Pitfalls:** -- **Auth:** Direct site URL with Basic auth returns **401**. Must use **Atlassian API gateway** with MCP auth header. Discover cloud UUID via `getVisibleJiraProjects`. +- **Auth:** Direct site URL (`{site}.atlassian.net`) with Basic auth returns **401**. Must use **Atlassian API gateway** (`https://api.atlassian.com/ex/jira/{cloudUuid}/rest/agile/1.0`) with the `Authorization` header from `.codeartsdoer/mcp/mcp_settings.json` (`mcpServers["atlassian-rovo-mcp"].headers.Authorization`). Any other auth token will fail. +- **Windows inline PowerShell:** The CodeArts Bash tool strips `$` from inline PowerShell commands. **Always write a `.ps1` script file first, then execute with `powershell -NoProfile -ExecutionPolicy Bypass -File "path/to/script.ps1"`**. - **Sprint name:** Must be **shorter than 30 characters** or API returns 400 - **Adding issues to sprint:** Use `atlassian-rovo-mcp_editJiraIssue` with `customfield_10020: ` (number, not array) - **Starting sprint:** PUT body must include `state`, `name`, `startDate`, and `endDate`. Sprint must be in `future` state @@ -443,6 +430,7 @@ Before approving release, verify ALL of the following: ### 7.4 Release Tagging - Create GitHub release tag via `github_create_or_update_file` or bash `git tag` +- Record the approved immutable image digest or SHA tag for deployment handoff - Update Jira fixVersions field on all released tasks --- @@ -488,36 +476,24 @@ Before approving release, verify ALL of the following: > **WARNING:** `PUT /sprint/{id}` does NOT support partial updates. > Must GET sprint first to fetch existing fields, then PUT with complete body. -**Windows (PowerShell):** -```powershell -# Reuse $headers, $baseUrl, $sprintId from Section 2.2 auth setup -# Sprint must be in "active" state to close +> **CRITICAL — Auth & URL:** Direct site URL (`{site}.atlassian.net`) always returns 401. +> You MUST use the Atlassian API gateway URL (`https://api.atlassian.com/ex/jira/{cloudUuid}/rest/agile/1.0`) +> with the `Authorization` header from `.codeartsdoer/mcp/mcp_settings.json` +> (`mcpServers["atlassian-rovo-mcp"].headers.Authorization`). Any other auth token will fail. -# Step 1: GET sprint to fetch existing fields -$uri = "${baseUrl}/sprint/${sprintId}"; $sprint = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers +> **Windows:** The CodeArts Bash tool strips `$` from inline PowerShell commands. +> Use the cross-platform template scripts from `references/templates/sprint-scripts/`: +> - Copy `sprint-close.ps1` (or `sprint-close.sh` on macOS/Linux) to the project root +> - Replace all `` values with actual values +> - Execute: `powershell -NoProfile -ExecutionPolicy Bypass -File "sprint-close.ps1"` +> - **Delete the script file after execution** (it contains auth tokens) -# Step 2: PUT with complete body (all required fields) -$endDate = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ss.fffZ") -$body = @{ state = "closed"; name = $sprint.name; startDate = $sprint.startDate; endDate = $endDate; goal = $sprint.goal } | ConvertTo-Json -$response = Invoke-RestMethod -Uri $uri -Method Put -Headers $headers -Body $body -# Verify $response.state == "closed" -``` +Template scripts are available at `references/templates/sprint-scripts/`: -**macOS/Linux (Bash):** -```bash -# Reuse $authHeader, $baseUrl, $sprintId from Section 2.2 auth setup -# Sprint must be in "active" state to close - -# Step 1: GET sprint to fetch existing fields -sprint=$(curl -s -H "Authorization: $authHeader" "${baseUrl}/sprint/${sprintId}") - -# Step 2: PUT with complete body (all required fields) -endDate=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z") -body=$(echo "$sprint" | jq --arg state "closed" --arg endDate "$endDate" \ - '{state: $state, name: .name, startDate: .startDate, endDate: $endDate, goal: .goal}') -response=$(curl -s -X PUT -H "Authorization: $authHeader" -H "Content-Type: application/json" -d "$body" "${baseUrl}/sprint/${sprintId}") -# Verify: echo "$response" | jq -r '.state' -``` +| Script | Platform | Usage | +|--------|----------|-------| +| `sprint-close.ps1` | Windows | `powershell -NoProfile -ExecutionPolicy Bypass -File "sprint-close.ps1"` | +| `sprint-close.sh` | macOS/Linux | `chmod +x sprint-close.sh && ./sprint-close.sh` | ### 9.3 Sprint Summary & Metrics - Get all issues in the closed sprint to compute velocity: diff --git a/skills/sdlc-agentic-pipeline/references/pipeline.md b/skills/sdlc-agentic-pipeline/references/pipeline.md index 759be09..050e483 100644 --- a/skills/sdlc-agentic-pipeline/references/pipeline.md +++ b/skills/sdlc-agentic-pipeline/references/pipeline.md @@ -43,11 +43,11 @@ Step 1: PM Agent — Requirement Breakdown (PRD + GitHub + Jira) > **Idempotency:** If the pipeline is re-run for the same sprint, the PM Agent must: > 1. Check if a sprint already exists and is active (skip Step 2 sprint creation) > 2. Check existing Jira tasks (skip Step 1 if tasks already created) -> 3. Check PR status (skip Steps 3-5b if PRs already merged into `dev`) +> 3. Check PR status (skip Steps 3-5 if PRs already merged into `dev`) > 4. Check CI/CD workflow runs (skip Step 6 if already passed) -> 5. Check JFrog artifacts (skip Step 7 if already verified) -> 6. Check if `dev` is already merged to `main` (skip Step 8 if already merged) -> 7. Check if deployment is already live (skip Step 9 if health check passes) +> 5. Check JFrog artifacts (skip Step 6 if already verified) +> 6. Check if `dev` is already merged to `main` (skip Step 7 if already merged) +> 7. Check if deployment is already live (skip Step 8 if health check passes) > 8. Always run Step 9 (sprint close + report) if not yet completed ### Step 1: PM Agent — Requirement Breakdown @@ -87,7 +87,7 @@ Step 1: PM Agent — Requirement Breakdown (PRD + GitHub + Jira) - **Error throwback**: If review flags issues, PM Agent revises requirements and re-requests review ### Step 2: PM Agent — Sprint Start & SDD Setup -- **Owner**: PM Agent +- **Owner**: PM Agent (sprint) + Developer Agent (SDD file writes) - **Tools**: Jira MCP, Bash (Jira Agile REST API), creating-sdd-directory skill, question tool - **Actions**: 1. Find Jira board ID via REST API: `GET /rest/agile/1.0/board` @@ -97,9 +97,12 @@ Step 1: PM Agent — Requirement Breakdown (PRD + GitHub + Jira) 4. Add all issues to sprint via REST API: `POST /rest/agile/1.0/sprint/{id}/issue` 5. Start sprint (set state to "active"): `PUT /rest/agile/1.0/sprint/{id}` 6. Invoke `creating-sdd-directory` skill for each task to initialize spec-driven development - 7. Populate spec.md, design.md, tasks.md from Jira requirements + 7. **Delegate SDD file creation to a developer agent** (the PM Agent is read-only with the repo): + - The developer agent creates `spec.md`, `design.md`, `tasks.md` from Jira requirements + - The developer agent works on a docs branch (e.g., `docs/sdd-`), commits, pushes, and creates a PR to `dev` + - The developer agent merges the PR after user review 8. Post SDD-complete comments on all Jira tasks -- **Output**: Active sprint with all issues, SDD directories created +- **Output**: Active sprint with all issues, SDD directories created and merged to `dev` ### Step 3: Frontend/Backend Agent — Development, Semgrep Pre-Scan & Fix - **Owner**: Frontend Agent, Backend Agent @@ -180,8 +183,8 @@ Step 1: PM Agent — Requirement Breakdown (PRD + GitHub + Jira) - **Includes**: build (Stage 1), sonar-scan (Stage 2), sonar-qg-check (Stage 3), deploy-to-jfrog (Stage 4), verify-jfrog (Stage 5). Uses sonarcloud-github-action@master (NOT sonarqube-scan-action) - **Actions**: 1. **Transition Jira task to "In Progress"** (CI/CD phase - task moves from "In Testing" back to "In Progress" to indicate active pipeline work) - 2. Verify/update GitHub Actions workflow (SonarCloud scan → build → JFrog upload on manual dispatch) - 3. **Monitor auto-triggered CI/CD (auto-triggers on dev push)** and **monitor workflow runs** — see `references/agents/devops-agent.md` §6.5–6.6 for detailed PowerShell and Bash commands + 2. Verify/update GitHub Actions workflow (SonarCloud scan → build → JFrog upload; auto-triggered on push to `dev`) + 3. **Monitor auto-triggered CI/CD** (auto-triggers on dev push) and **monitor workflow runs** — see `references/agents/devops-agent.md` §6.5–6.6 for detailed PowerShell and Bash commands 4. If CI fails → identify failing job+step: - **Build/test error** (Stage 2 fails): transition Jira BACK to "In Progress", comment `@agent:frontend` or `@agent:backend Build/test failed at : ` - **Pipeline config error** (Stage 1/3 fails, workflow YAML issue): DevOps self-fixes, re-trigger pipeline @@ -194,7 +197,7 @@ Step 1: PM Agent — Requirement Breakdown (PRD + GitHub + Jira) - **NOTE**: Upload is handled by GitHub Actions pipeline. Agent only VERIFIES. If JFrog MCP is unavailable, use the JFrog Artifactory REST API as a fallback. - **Authentication**: Bearer token in `Authorization` header -- **REST API Endpoints** (base URL: `https:///artifactory/api/`): +- **REST API Endpoints** (base URL: `/artifactory/api/` — the URL already includes the scheme): 1. **List repositories**: `GET /artifactory/api/repositories` — verify repo exists 2. **List artifacts in repo**: `GET /artifactory/api/storage/` — find Docker image 3. **List image tags**: `GET /artifactory/api/storage//` — verify tags (latest + commit SHA) @@ -265,14 +268,25 @@ Step 1: PM Agent — Requirement Breakdown (PRD + GitHub + Jira) - Option 1: "Wait" -> pause Step 9 until all tasks are Done - Option 2: "Move to next sprint" -> move incomplete tasks to the next sprint (remove from current sprint via `customfield_10020` update), then proceed with closing - Option 3: "Close as Won't Do" -> mark incomplete tasks as "Won't Do" and proceed with closing - 2. Close sprint via REST API: `PUT /rest/agile/1.0/sprint/{id}` - - **WARNING:** The Jira Agile REST API does NOT support partial updates. - You must send the FULL sprint object, not just the changed field. - - ❌ Wrong: `{ "state": "closed" }` → 400 Bad Request - - ✅ Right: `{ "state": "closed", "name": "...", "startDate": "...", "endDate": "...", "goal": "..." }` - - **Solution:** First `GET /rest/agile/1.0/sprint/{id}` to fetch existing `name` and `startDate`, - then `PUT` with the complete body including all required fields. - - Required fields: `state`, `name`, `startDate`, `endDate` (set to current time) + 2. Close sprint via REST API: `PUT /rest/agile/1.0/sprint/{id}` + - **WARNING:** The Jira Agile REST API does NOT support partial updates. + You must send the FULL sprint object, not just the changed field. + - ❌ Wrong: `{ "state": "closed" }` → 400 Bad Request + - ✅ Right: `{ "state": "closed", "name": "...", "startDate": "...", "endDate": "...", "goal": "..." }` + - **Solution:** First `GET /rest/agile/1.0/sprint/{id}` to fetch existing `name` and `startDate`, + then `PUT` with the complete body including all required fields. + - Required fields: `state`, `name`, `startDate`, `endDate` (set to current time) + - **CRITICAL — Auth & URL:** Direct site URL (`{site}.atlassian.net`) always returns 401. + Must use the Atlassian API gateway (`https://api.atlassian.com/ex/jira/{cloudUuid}/rest/agile/1.0`) + with the `Authorization` header from `.codeartsdoer/mcp/mcp_settings.json` + (`mcpServers["atlassian-rovo-mcp"].headers.Authorization`). Any other auth token will fail. + - **Windows:** The CodeArts Bash tool strips `$` from inline PowerShell. Always write a `.ps1` + script file first, then execute with `powershell -NoProfile -ExecutionPolicy Bypass -File "path/to/script.ps1"`. + Delete the script file after execution. + - **Cross-platform templates** are available at `references/templates/sprint-scripts/`: + - `sprint-close.ps1` / `sprint-close.sh` — close an active sprint + - `sprint-start.ps1` / `sprint-start.sh` — start a future sprint + - Copy the appropriate script, replace `` values, execute, then delete. 3. Generate sprint summary (completed vs. incomplete, velocity metrics) 4. Post retrospective comment on the Epic 5. Archive SDD documents @@ -296,11 +310,10 @@ Step 1: PM Agent — Requirement Breakdown (PRD + GitHub + Jira) - Step 8: Deployment details (Docker pull, container start, health check HTTP code, deployment URL) - Sprint velocity chart (CSS-based bar chart) - Retrospective section: what went well, what didn't, action items - 7. **Push report to GitHub** - - Delegate to Developer Agent (Backend if both active, otherwise sole developer) - DIRECT PUSH to `dev` (no PR) - - Commit `reports/sdlc-report.html` and push directly to `dev` - - Create PR targeting `dev` (lightweight merge - docs only, no review gates) - - `reports/**` exempt from PR via path-based branch protection + 7. **Push report to GitHub** + - Delegate to Developer Agent (Backend if both active, otherwise sole developer) + - Create a docs branch (e.g., `docs/sdlc-reports`), commit `reports/sdlc-report.html`, push branch + - Create PR targeting `dev` and merge it (GitHub branch protection applies to the whole branch, so a PR is required) 8. **Present report to user** - Show file path to `reports/sdlc-report.html` - Show GitHub PR link where report was pushed @@ -336,7 +349,7 @@ See `references/agents/devops-agent.md` §6.5–6.6 for auth setup, trigger, and > Must be manually added: Settings -> Work items -> Workflows -> Edit -> Add status > -> Create 'In Testing' (category: In Progress) -> Enable 'Allow all statuses to > transition to this one'. See -eferences/setup/service-onboarding.md for details. +references/setup/service-onboarding.md for details. ## Agent Routing Labels, Domain Labels, Jira Comment Format, Jira Task Discovery JQL, Branch Naming Convention, PR Merge Gate diff --git a/skills/sdlc-agentic-pipeline/references/setup/service-onboarding.md b/skills/sdlc-agentic-pipeline/references/setup/service-onboarding.md index b8f522f..94defb7 100644 --- a/skills/sdlc-agentic-pipeline/references/setup/service-onboarding.md +++ b/skills/sdlc-agentic-pipeline/references/setup/service-onboarding.md @@ -108,8 +108,10 @@ automatically before any service onboarding - **no user action needed**. > - **Project level** — available only in this project (stored in `.codeartsdoer/skills/`) *(current default)* > > This determines where generated config files and skill references are stored. +> All subsequent skill, config, and reference source/target paths are derived from +> this selection (user-level: `~/.codeartsdoer/...`, project-level: `.codeartsdoer/...`). -Ask the user via the `question` tool which option they want. **Keep the question and option descriptions short** - do NOT include long explanations of agent roles or internal pipeline details. The user only needs to understand the choice, not the implementation: +Ask the user via the `question` tool which option they want. **Keep the question and option descriptions short** - do NOT include long explanations of agent roles or internal pipeline details. The user only needs to understand the choice, not the implementation. Store the selection for use in all subsequent path derivations. - **Question**: "Start with an existing GitHub repo or create a new one?"- **Option A**: "Existing repo" — description: "Use a repo you already have" - **Option B**: "New repo" — description: "Create a new repo from a prompt" @@ -370,7 +372,7 @@ before writing `docker-compose.yml`: vanilla HTML/CSS/JS for frontend) 2. **Invoke Backend Agent** to create repo, clone, build, create `dev` branch & push (PM Agent -> Task tool): - - Pass the backend scope, tech stack, project prompt, repo name, owner, visibility, AND GitHub PAT to the Backend Agent + - Pass the backend scope, tech stack, project prompt, repo name, owner, visibility to the Backend Agent (do NOT pass the GitHub PAT — the Backend Agent uses its preconfigured GitHub MCP capability for repository creation) - The Backend Agent creates the repo via GitHub MCP (this is the ONLY agent that creates repos): ``` github_create_repository( @@ -402,21 +404,30 @@ before writing `docker-compose.yml`: git push origin dev ``` -3. **Frontend Agent builds concurrently with Backend** (PM dispatches via Jira async): - - Pass the frontend scope, tech stack, and project prompt to the Frontend Agent - - The Frontend Agent generates: + 3. **Frontend Agent builds concurrently with Backend** (PM dispatches via Jira async): + - The Backend Agent has already created the repo, cloned it, and created the `dev` branch + - Pass the frontend scope, tech stack, project prompt, AND the repository URL to the Frontend Agent + - The Frontend Agent clones the repository from the URL provided by the Backend Agent + - The Frontend Agent works on an isolated feature branch (not directly on `dev`): + ```bash + git clone "https://github.com//.git" + cd + git checkout -b feature/frontend/initial-build dev + ``` + - The Frontend Agent generates: - Complete directory structure (`frontend/src/`, `frontend/public/`) - Actual implementation code for all UI features - Configuration files (`package.json`, frontend `Dockerfile`) - Component-level tests - - The Frontend Agent writes files into the cloned repo's `frontend/` directory - - The Frontend Agent commits frontend code and pushes to `dev`: - ```bash - cd - git add frontend/ - git commit -m "feat: initial frontend build from prompt" - git push origin dev - ``` + - The Frontend Agent writes files into the cloned repo's `frontend/` directory + - The Frontend Agent commits frontend code and pushes to its feature branch: + ```bash + git add frontend/ + git commit -m "feat: initial frontend build from prompt" + git push origin feature/frontend/initial-build + ``` + - After Backend Agent completes, the Frontend Agent (or Backend Agent if both active) + creates a PR from `feature/frontend/initial-build` to `dev` and merges it 4. **Invoke DevOps Agent** (after BOTH Backend + Frontend complete) to write `docker-compose.yml`, shared docs, generate `ci-cd.yml` & push to `dev` (PM Agent -> Task tool): - Pass the project structure, tech stack, container requirements, AND the @@ -801,7 +812,7 @@ When asking for JFrog credentials, show the example values and tips below in the question descriptions to help the user provide correct values. 1. **JFrog Platform URL** — Example: `https://demoartifacthw.jfrog.io/` - - **Tip:** Copy the full base URL from your browser address bar when logged into JFrog. + - **Tip:** Copy the full base URL from your browser address bar when logged into JFrog. The value **includes the scheme** (`https://`). 2. **JFrog Docker Registry** — Example: `demoartifacthw.jfrog.io` - **Tip:** In Administration > Repositories, create a Local repository with Docker package type. - **WARNING:** No underscores in repository name (DNS limitation). Use hyphens (e.g., `docker-dev-local`). @@ -872,15 +883,15 @@ for full instructions. ``` - Verify key-based SSH login works: - **Windows (PowerShell):** - ```powershell - ssh -i $sshKey -o BatchMode=yes -o StrictHostKeyChecking=no @ "echo OK" - ``` + **Windows (PowerShell):** + ```powershell + ssh -i $sshKey -o BatchMode=yes @ "echo OK" + ``` - **macOS/Linux (Bash):** - ```bash - ssh -i "$sshKey" -o BatchMode=yes -o StrictHostKeyChecking=no @ "echo OK" - ``` + **macOS/Linux (Bash):** + ```bash + ssh -i "$sshKey" -o BatchMode=yes @ "echo OK" + ``` 4. **Install Docker on ECS** (handled automatically via SSH): **Windows (PowerShell):** @@ -1219,15 +1230,15 @@ Once all service info is confirmed and saved: repository root during CI/CD. Without it, the scan fails. - The DevOps Agent should commit this alongside `ci-cd.yml` and `docker-compose.yml` when pushing the initial codebase to the `dev` branch in Step 0.1.B.4. - - If not pushed during Step 0.1.B.4, delegate to the Backend Agent (or sole developer agent) - DIRECT PUSH to dev (no PR, path-based branch protection for .opencode/**): - ``` - git checkout dev - git checkout -b docs/sonar-config - git add sonar-project.properties - git commit -m "chore: add sonar-project.properties for CI/CD SonarCloud scan" - git push origin docs/sonar-config - # Developer Agent DIRECT PUSH to dev (no PR - path-based branch protection) - ``` + - If not pushed during Step 0.1.B.4, delegate to the Backend Agent (or sole developer agent) - create a docs branch + PR targeting `dev`: + ``` + git checkout dev + git checkout -b docs/sonar-config + git add sonar-project.properties + git commit -m "chore: add sonar-project.properties for CI/CD SonarCloud scan" + git push origin docs/sonar-config + # Developer Agent creates PR and merges to dev + ``` 4. Generate `.env` from template (see `references/templates/env-template.env`) - **Local only** - contains secrets, do NOT commit to repo 5. Run `set-secrets.js` to set GitHub Secrets and Variables automatically diff --git a/skills/sdlc-agentic-pipeline/references/templates/add_ssh_key.py b/skills/sdlc-agentic-pipeline/references/templates/add_ssh_key.py index e98591f..7eb9418 100644 --- a/skills/sdlc-agentic-pipeline/references/templates/add_ssh_key.py +++ b/skills/sdlc-agentic-pipeline/references/templates/add_ssh_key.py @@ -6,11 +6,21 @@ ECS_USER = "" ECS_PASSWORD = "" +KNOWN_HOSTS_PATH = os.path.expanduser("~/.ssh/known_hosts") + def add_ssh_key(): ssh = paramiko.SSHClient() - ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + if os.path.exists(KNOWN_HOSTS_PATH): + ssh.load_host_keys(KNOWN_HOSTS_PATH) + ssh.set_missing_host_key_policy(paramiko.RejectPolicy()) print(f"Connecting to {ECS_USER}@{ECS_HOST}...") - ssh.connect(ECS_HOST, username=ECS_USER, password=ECS_PASSWORD, timeout=15) + try: + ssh.connect(ECS_HOST, username=ECS_USER, password=ECS_PASSWORD, timeout=15) + except paramiko.SSHException as e: + print(f"ERROR: Host key verification failed for {ECS_HOST}.") + print(f"Verify the ECS host fingerprint first: ssh-keyscan {ECS_HOST} >> {KNOWN_HOSTS_PATH}") + print(f"Then re-run this script.") + sys.exit(1) pub_key_path = os.path.expanduser("~/.ssh/id_rsa.pub") if not os.path.exists(pub_key_path): @@ -33,6 +43,8 @@ def add_ssh_key(): print("ERROR: Failed to add SSH key.") if err: print("STDERR:", err) + ssh.close() + sys.exit(1) ssh.close() @@ -41,7 +53,7 @@ def add_ssh_key(): import subprocess ssh_key = os.path.expanduser("~/.ssh/id_rsa") verify = subprocess.run( - ["ssh", "-i", ssh_key, "-o", "BatchMode=yes", "-o", "StrictHostKeyChecking=no", + ["ssh", "-i", ssh_key, "-o", "BatchMode=yes", "-o", "StrictHostKeyChecking=accept-new", "-o", "ConnectTimeout=10", f"{ECS_USER}@{ECS_HOST}", "echo VERIFIED"], capture_output=True, text=True, timeout=15 ) @@ -52,4 +64,4 @@ def add_ssh_key(): print(verify.stderr) if __name__ == "__main__": - add_ssh_key() \ No newline at end of file + add_ssh_key() diff --git a/skills/sdlc-agentic-pipeline/references/templates/ci-cd.yml b/skills/sdlc-agentic-pipeline/references/templates/ci-cd.yml index 1d1ea04..35c9930 100644 --- a/skills/sdlc-agentic-pipeline/references/templates/ci-cd.yml +++ b/skills/sdlc-agentic-pipeline/references/templates/ci-cd.yml @@ -145,6 +145,8 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + with: + args: -Dsonar.qualitygate.wait=true sonar-qg-check: needs: @@ -219,10 +221,17 @@ jobs: push: true tags: | ${{ env.JF_DOCKER_REGISTRY }}//:${{ github.sha }} - ${{ env.JF_DOCKER_REGISTRY }}//:latest cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max + - name: Publish image digest as release artifact + run: | + DIGEST=$(docker buildx imagetools inspect ${{ env.JF_DOCKER_REGISTRY }}//:${{ github.sha }} --format '{{.Digest}}' 2>/dev/null || echo "") + echo "RELEASE_IMAGE=${{ env.JF_DOCKER_REGISTRY }}//:${{ github.sha }}" >> $GITHUB_ENV + echo "RELEASE_DIGEST=${DIGEST}" >> $GITHUB_ENV + echo "Deployable image: ${{ env.JF_DOCKER_REGISTRY }}//:${{ github.sha }}" + echo "Digest: ${DIGEST}" + - name: Move Docker cache run: | rm -rf /tmp/.buildx-cache diff --git a/skills/sdlc-agentic-pipeline/references/templates/env-template.env b/skills/sdlc-agentic-pipeline/references/templates/env-template.env index 616972f..1680475 100644 --- a/skills/sdlc-agentic-pipeline/references/templates/env-template.env +++ b/skills/sdlc-agentic-pipeline/references/templates/env-template.env @@ -6,6 +6,8 @@ JIRA_PROJECT_KEY= # SonarCloud MCP SONAR_PROJECT_KEY= +SONAR_ORGANIZATION= +SONAR_TOKEN= # Semgrep MCP SEMGREP_APP_TOKEN= diff --git a/skills/sdlc-agentic-pipeline/references/templates/mcp-settings.json b/skills/sdlc-agentic-pipeline/references/templates/mcp-settings.json index e068c2a..be6596c 100644 --- a/skills/sdlc-agentic-pipeline/references/templates/mcp-settings.json +++ b/skills/sdlc-agentic-pipeline/references/templates/mcp-settings.json @@ -32,7 +32,7 @@ "jfrog": { "url": "/mcp", "headers": { - "Authorization": "Bearer " + "Authorization": "Bearer " } } } diff --git a/skills/sdlc-agentic-pipeline/references/templates/set-secrets.js b/skills/sdlc-agentic-pipeline/references/templates/set-secrets.js index fd008e7..055ea1e 100644 --- a/skills/sdlc-agentic-pipeline/references/templates/set-secrets.js +++ b/skills/sdlc-agentic-pipeline/references/templates/set-secrets.js @@ -37,6 +37,7 @@ const CONFIG = { JFROG_DOCKER_REGISTRY: '', JFROG_USERNAME: '', JFROG_PROJECT: '', + SONAR_PROJECT_KEY: '', }, }; @@ -127,15 +128,20 @@ async function main() { console.log(`\nSetting GitHub Actions secrets and variables for ${GITHUB_OWNER}/${GITHUB_REPO}\n`); console.log('Variables (plain text):'); + let failed = false; for (const [name, value] of Object.entries(VARIABLES)) { - await setVariable(GITHUB_OWNER, GITHUB_REPO, GITHUB_PAT, name, value); + failed ||= !(await setVariable(GITHUB_OWNER, GITHUB_REPO, GITHUB_PAT, name, value)); } console.log('\nSecrets (encrypted):'); for (const [name, value] of Object.entries(SECRETS)) { - await setSecret(GITHUB_OWNER, GITHUB_REPO, GITHUB_PAT, name, value); + failed ||= !(await setSecret(GITHUB_OWNER, GITHUB_REPO, GITHUB_PAT, name, value)); } + if (failed) { + console.error('\nERROR: One or more secrets or variables failed to update.'); + process.exit(1); + } console.log('\nDone. Verify at: https://github.com/' + GITHUB_OWNER + '/' + GITHUB_REPO + '/settings/secrets/actions'); } diff --git a/skills/sdlc-agentic-pipeline/references/templates/sprint-scripts/README.md b/skills/sdlc-agentic-pipeline/references/templates/sprint-scripts/README.md new file mode 100644 index 0000000..c0cc4d6 --- /dev/null +++ b/skills/sdlc-agentic-pipeline/references/templates/sprint-scripts/README.md @@ -0,0 +1,35 @@ +# Sprint Management Scripts (Cross-Platform Templates) + +Templates for managing Jira sprints via the Atlassian API gateway. +Used by the PM Agent in Steps 2 (sprint start) and 9 (sprint close). + +## Files + +| File | Platform | Purpose | +|------|----------|---------| +| `sprint-start.ps1` | Windows | Start a future sprint (set state to "active") | +| `sprint-start.sh` | macOS/Linux | Start a future sprint (set state to "active") | +| `sprint-close.ps1` | Windows | Close an active sprint (set state to "closed") | +| `sprint-close.sh` | macOS/Linux | Close an active sprint (set state to "closed") | + +## Prerequisites + +- **Cloud UUID**: Discovered via `atlassian-rovo-mcp_getVisibleJiraProjects`. + Extract the UUID from the `self` URL in the response: + `https://api.atlassian.com/ex/jira/{cloudUuid}/rest/api/3/...` +- **Auth header**: Read from `.codeartsdoer/mcp/mcp_settings.json`, + key: `mcpServers["atlassian-rovo-mcp"].headers.Authorization` +- **Board ID**: Found by listing boards and filtering by project key + +## Critical Rules + +1. **Never use the site URL** (`{site}.atlassian.net`) — it always returns 401. + Always use the gateway: `https://api.atlassian.com/ex/jira/{cloudUuid}/rest/agile/1.0` +2. **Never use any auth token** other than the one from `mcp_settings.json`. +3. **Windows**: The CodeArts Bash tool strips `$` from inline PowerShell. + Always write a `.ps1` file first, then execute with: + `powershell -NoProfile -ExecutionPolicy Bypass -File "script.ps1"` +4. **Sprint name** must be shorter than 30 characters. +5. **PUT requires full object** — partial updates return 400. + Always GET the sprint first, then PUT with all required fields. +6. **Delete script files** after execution (they contain auth tokens). \ No newline at end of file diff --git a/skills/sdlc-agentic-pipeline/references/templates/sprint-scripts/sprint-close.ps1 b/skills/sdlc-agentic-pipeline/references/templates/sprint-scripts/sprint-close.ps1 new file mode 100644 index 0000000..f802f6c --- /dev/null +++ b/skills/sdlc-agentic-pipeline/references/templates/sprint-scripts/sprint-close.ps1 @@ -0,0 +1,75 @@ +# sprint-close.ps1 - Close a Jira Sprint (Windows Template) +# +# USAGE: +# 1. Replace all values below +# 2. Execute via CodeArts Bash tool: +# powershell -NoProfile -ExecutionPolicy Bypass -File "sprint-close.ps1" +# 3. Delete this file after execution +# +# VALUES SOURCE: +# - CLOUD_UUID: from atlassian-rovo-mcp_getVisibleJiraProjects (extract from self URL) +# - AUTH_HEADER: from .codeartsdoer/mcp/mcp_settings.json -> mcpServers["atlassian-rovo-mcp"].headers.Authorization +# - SPRINT_ID: the sprint to close +# +# CRITICAL: +# - Do NOT use {site}.atlassian.net — always use api.atlassian.com gateway +# - Do NOT use any auth token except the one from mcp_settings.json +# - PUT requires FULL object (partial updates return 400) +# - Sprint must be in "active" state to close +# - Always GET sprint first to fetch existing name/startDate/goal + +# ============================================================ +# CONFIG — Replace all values +# ============================================================ + +$cloudUuid = "" # e.g. "0a03a862-9e72-4256-af89-a6c4c96cf0e8" +$authHeader = "" # e.g. "Basic Y29kZWFydHN0ZXN0..." +$sprintId = "" # e.g. 232 + +# ============================================================ +# EXECUTION — Do not edit below +# ============================================================ + +$baseUrl = "https://api.atlassian.com/ex/jira/${cloudUuid}/rest/agile/1.0" +$headers = @{ + Authorization = $authHeader + "Content-Type" = "application/json" +} + +# Step 1: GET sprint to fetch existing fields +Write-Output "Step 1: Fetching sprint ${sprintId}..." +$uri = "${baseUrl}/sprint/${sprintId}" +$sprint = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers +Write-Output " Name: $($sprint.name)" +Write-Output " State: $($sprint.state)" +Write-Output " StartDate: $($sprint.startDate)" + +if ($sprint.state -ne "active") { + Write-Output "ERROR: Sprint is in '$($sprint.state)' state. Must be 'active' to close." + exit 1 +} + +# Step 2: PUT with complete body (all required fields) +Write-Output "" +Write-Output "Step 2: Closing sprint..." +$endDate = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ss.fffZ") + +$body = @{ + state = "closed" + name = $sprint.name + startDate = $sprint.startDate + endDate = $endDate + goal = $sprint.goal +} | ConvertTo-Json + +$response = Invoke-RestMethod -Uri $uri -Method Put -Headers $headers -Body $body +Write-Output " Result state: $($response.state)" + +if ($response.state -eq "closed") { + Write-Output "" + Write-Output "SUCCESS: Sprint closed." +} else { + Write-Output "" + Write-Output "ERROR: Sprint state is '$($response.state)', expected 'closed'." + exit 1 +} \ No newline at end of file diff --git a/skills/sdlc-agentic-pipeline/references/templates/sprint-scripts/sprint-close.sh b/skills/sdlc-agentic-pipeline/references/templates/sprint-scripts/sprint-close.sh new file mode 100644 index 0000000..4b885a3 --- /dev/null +++ b/skills/sdlc-agentic-pipeline/references/templates/sprint-scripts/sprint-close.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +# sprint-close.sh - Close a Jira Sprint (macOS/Linux Template) +# +# USAGE: +# 1. Replace all values below +# 2. Run: chmod +x sprint-close.sh && ./sprint-close.sh +# 3. Delete this file after execution +# +# VALUES SOURCE: +# - CLOUD_UUID: from atlassian-rovo-mcp_getVisibleJiraProjects (extract from self URL) +# - AUTH_HEADER: from .codeartsdoer/mcp/mcp_settings.json -> mcpServers["atlassian-rovo-mcp"].headers.Authorization +# - SPRINT_ID: the sprint to close +# +# CRITICAL: +# - Do NOT use {site}.atlassian.net — always use api.atlassian.com gateway +# - Do NOT use any auth token except the one from mcp_settings.json +# - PUT requires FULL object (partial updates return 400) +# - Sprint must be in "active" state to close +# - Always GET sprint first to fetch existing name/startDate/goal + +# ============================================================ +# CONFIG — Replace all values +# ============================================================ + +CLOUD_UUID="" # e.g. "0a03a862-9e72-4256-af89-a6c4c96cf0e8" +AUTH_HEADER="" # e.g. "Basic Y29kZWFydHN0ZXN0..." +SPRINT_ID="" # e.g. 232 + +# ============================================================ +# EXECUTION — Do not edit below +# ============================================================ + +BASE_URL="https://api.atlassian.com/ex/jira/${CLOUD_UUID}/rest/agile/1.0" + +# Step 1: GET sprint to fetch existing fields +echo "Step 1: Fetching sprint ${SPRINT_ID}..." +sprint=$(curl -s -H "Authorization: ${AUTH_HEADER}" "${BASE_URL}/sprint/${SPRINT_ID}") +state=$(echo "$sprint" | jq -r '.state') +name=$(echo "$sprint" | jq -r '.name') +startDate=$(echo "$sprint" | jq -r '.startDate') +echo " Name: $name" +echo " State: $state" +echo " StartDate: $startDate" + +if [ "$state" != "active" ]; then + echo "ERROR: Sprint is in '$state' state. Must be 'active' to close." + exit 1 +fi + +# Step 2: PUT with complete body (all required fields) +echo "" +echo "Step 2: Closing sprint..." +endDate=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z") + +body=$(echo "$sprint" | jq --arg state "closed" --arg endDate "$endDate" \ + '{state: $state, name: .name, startDate: .startDate, endDate: $endDate, goal: .goal}') + +response=$(curl -s -X PUT -H "Authorization: ${AUTH_HEADER}" -H "Content-Type: application/json" -d "$body" "${BASE_URL}/sprint/${SPRINT_ID}") +resultState=$(echo "$response" | jq -r '.state') + +if [ "$resultState" = "closed" ]; then + echo "" + echo "SUCCESS: Sprint closed." +else + echo "" + echo "ERROR: Sprint state is '$resultState', expected 'closed'." + exit 1 +fi \ No newline at end of file diff --git a/skills/sdlc-agentic-pipeline/references/templates/sprint-scripts/sprint-start.ps1 b/skills/sdlc-agentic-pipeline/references/templates/sprint-scripts/sprint-start.ps1 new file mode 100644 index 0000000..18579a7 --- /dev/null +++ b/skills/sdlc-agentic-pipeline/references/templates/sprint-scripts/sprint-start.ps1 @@ -0,0 +1,80 @@ +# sprint-start.ps1 - Start a Jira Sprint (Windows Template) +# +# USAGE: +# 1. Replace all values below +# 2. Execute via CodeArts Bash tool: +# powershell -NoProfile -ExecutionPolicy Bypass -File "sprint-start.ps1" +# 3. Delete this file after execution +# +# VALUES SOURCE: +# - CLOUD_UUID: from atlassian-rovo-mcp_getVisibleJiraProjects (extract from self URL) +# - AUTH_HEADER: from .codeartsdoer/mcp/mcp_settings.json -> mcpServers["atlassian-rovo-mcp"].headers.Authorization +# - BOARD_ID: from GET /rest/agile/1.0/board (filter by project key) +# - SPRINT_ID: from POST /rest/agile/1.0/sprint (after creating the sprint) +# +# CRITICAL: +# - Do NOT use {site}.atlassian.net — always use api.atlassian.com gateway +# - Do NOT use any auth token except the one from mcp_settings.json +# - Sprint name must be < 30 characters +# - Sprint must be in "future" state before starting + +# ============================================================ +# CONFIG — Replace all values +# ============================================================ + +$cloudUuid = "" # e.g. "0a03a862-9e72-4256-af89-a6c4c96cf0e8" +$authHeader = "" # e.g. "Basic Y29kZWFydHN0ZXN0..." +$boardId = "" # e.g. 42 +$sprintId = "" # e.g. 232 +$sprintName = "" # e.g. "Sprint 2 - Features" (max 30 chars!) +$sprintGoal = "" # e.g. "Deliver feature X, Y, Z" + +# ============================================================ +# EXECUTION — Do not edit below +# ============================================================ + +$baseUrl = "https://api.atlassian.com/ex/jira/${cloudUuid}/rest/agile/1.0" +$headers = @{ + Authorization = $authHeader + "Content-Type" = "application/json" +} + +# Step 1: Verify sprint exists and is in "future" state +Write-Output "Step 1: Verifying sprint ${sprintId}..." +$uri = "${baseUrl}/sprint/${sprintId}" +$sprint = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers +Write-Output " Name: $($sprint.name)" +Write-Output " State: $($sprint.state)" + +if ($sprint.state -ne "future") { + Write-Output "ERROR: Sprint is in '$($sprint.state)' state. Must be 'future' to start." + exit 1 +} + +# Step 2: Start sprint (PUT with full object) +Write-Output "" +Write-Output "Step 2: Starting sprint..." +$startDate = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ss.fffZ") +$endDate = (Get-Date).AddDays(14).ToString("yyyy-MM-ddTHH:mm:ss.fffZ") + +$body = @{ + state = "active" + name = $sprint.name + startDate = $startDate + endDate = $endDate + goal = $sprintGoal +} | ConvertTo-Json + +$response = Invoke-RestMethod -Uri $uri -Method Put -Headers $headers -Body $body +Write-Output " Result state: $($response.state)" +Write-Output " Start date: $($response.startDate)" +Write-Output " End date: $($response.endDate)" + +if ($response.state -eq "active") { + Write-Output "" + Write-Output "SUCCESS: Sprint started." +} else { + Write-Output "" + Write-Output "ERROR: Sprint state is '$($response.state)', expected 'active'." + exit 1 +} \ No newline at end of file diff --git a/skills/sdlc-agentic-pipeline/references/templates/sprint-scripts/sprint-start.sh b/skills/sdlc-agentic-pipeline/references/templates/sprint-scripts/sprint-start.sh new file mode 100644 index 0000000..ba344e2 --- /dev/null +++ b/skills/sdlc-agentic-pipeline/references/templates/sprint-scripts/sprint-start.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +# sprint-start.sh - Start a Jira Sprint (macOS/Linux Template) +# +# USAGE: +# 1. Replace all values below +# 2. Run: chmod +x sprint-start.sh && ./sprint-start.sh +# 3. Delete this file after execution +# +# VALUES SOURCE: +# - CLOUD_UUID: from atlassian-rovo-mcp_getVisibleJiraProjects (extract from self URL) +# - AUTH_HEADER: from .codeartsdoer/mcp/mcp_settings.json -> mcpServers["atlassian-rovo-mcp"].headers.Authorization +# - BOARD_ID: from GET /rest/agile/1.0/board (filter by project key) +# - SPRINT_ID: from POST /rest/agile/1.0/sprint (after creating the sprint) +# +# CRITICAL: +# - Do NOT use {site}.atlassian.net — always use api.atlassian.com gateway +# - Do NOT use any auth token except the one from mcp_settings.json +# - Sprint name must be < 30 characters +# - Sprint must be in "future" state before starting + +# ============================================================ +# CONFIG — Replace all values +# ============================================================ + +CLOUD_UUID="" # e.g. "0a03a862-9e72-4256-af89-a6c4c96cf0e8" +AUTH_HEADER="" # e.g. "Basic Y29kZWFydHN0ZXN0..." +BOARD_ID="" # e.g. 42 +SPRINT_ID="" # e.g. 232 +SPRINT_GOAL="" # e.g. "Deliver feature X, Y, Z" + +# ============================================================ +# EXECUTION — Do not edit below +# ============================================================ + +BASE_URL="https://api.atlassian.com/ex/jira/${CLOUD_UUID}/rest/agile/1.0" + +# Step 1: Verify sprint exists and is in "future" state +echo "Step 1: Verifying sprint ${SPRINT_ID}..." +sprint=$(curl -s -H "Authorization: ${AUTH_HEADER}" "${BASE_URL}/sprint/${SPRINT_ID}") +state=$(echo "$sprint" | jq -r '.state') +name=$(echo "$sprint" | jq -r '.name') +echo " Name: $name" +echo " State: $state" + +if [ "$state" != "future" ]; then + echo "ERROR: Sprint is in '$state' state. Must be 'future' to start." + exit 1 +fi + +# Step 2: Start sprint (PUT with full object) +echo "" +echo "Step 2: Starting sprint..." +startDate=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z") +endDate=$(date -u -v+14d +"%Y-%m-%dT%H:%M:%S.000Z" 2>/dev/null || date -u -d "+14 days" +"%Y-%m-%dT%H:%M:%S.000Z") + +body=$(echo "$sprint" | jq --arg state "active" --arg startDate "$startDate" --arg endDate "$endDate" --arg goal "$SPRINT_GOAL" \ + '{state: $state, name: .name, startDate: $startDate, endDate: $endDate, goal: $goal}') + +response=$(curl -s -X PUT -H "Authorization: ${AUTH_HEADER}" -H "Content-Type: application/json" -d "$body" "${BASE_URL}/sprint/${SPRINT_ID}") +resultState=$(echo "$response" | jq -r '.state') +echo " Result state: $resultState" +echo " Start date: $(echo "$response" | jq -r '.startDate')" +echo " End date: $(echo "$response" | jq -r '.endDate')" + +if [ "$resultState" = "active" ]; then + echo "" + echo "SUCCESS: Sprint started." +else + echo "" + echo "ERROR: Sprint state is '$resultState', expected 'active'." + exit 1 +fi \ No newline at end of file From 9cf66f582bee14846f4ae47de51fd16a796c32a2 Mon Sep 17 00:00:00 2001 From: agentman3334 Date: Sat, 18 Jul 2026 12:42:11 +0300 Subject: [PATCH 2/2] fix(sdlc-pipeline): remove stale direct-push refs, fix f-string lint, remove redundant QG job - SKILL.md: replace remaining 'direct push' references with PR-based flow (heading, warning #10, step 7 conflict resolution) - SKILL.md: fix conflict resolution description from 'prefer dev' blanket strategy to domain-owner strategy - add_ssh_key.py: remove extraneous f-string prefix (Ruff F541) - ci-cd.yml: remove redundant sonar-qg-check job since sonar.qualitygate.wait=true already blocks on QG result; deploy-to-jfrog now depends directly on sonar-scan --- skills/sdlc-agentic-pipeline/SKILL.md | 12 +++---- .../references/templates/add_ssh_key.py | 2 +- .../references/templates/ci-cd.yml | 33 ++++--------------- 3 files changed, 14 insertions(+), 33 deletions(-) diff --git a/skills/sdlc-agentic-pipeline/SKILL.md b/skills/sdlc-agentic-pipeline/SKILL.md index 123d080..c8b3a26 100644 --- a/skills/sdlc-agentic-pipeline/SKILL.md +++ b/skills/sdlc-agentic-pipeline/SKILL.md @@ -170,7 +170,7 @@ See `references/templates/mcp-settings.json` for the template. 1. **Parallel dispatch via Jira async**: Backend + Frontend agents work simultaneously (Steps 0, 1b, 3). PM dispatches via Jira comments, both agents pick up independently. 2. **Batch Jira operations**: Bulk create API for tasks (Step 1), batch transitions. -3. **Direct push for docs/reports**: `.opencode/**`, `docs/**`, `reports/**` paths +3. **PR-based flow for docs/reports**: `.opencode/**`, `docs/**`, `reports/**` paths use a docs branch + PR targeting `dev` (GitHub branch protection applies to the whole branch, not individual paths, so a PR is required even for documentation changes). 4. **Auto-trigger CI/CD**: `on: push` to `dev` branch. No manual DevOps trigger (Step 5->6). @@ -633,8 +633,8 @@ The pipeline requires explicit human approval at these points: > must go through a feature/docs branch and PR targeting `dev`. Enable GitHub branch > protection rules on both `main` and `dev` (Settings > Branches > Branch protection > rules) to enforce this. `main` is only updated via `dev` → `main` merge at release -> time (Step 7). SDD docs use direct push (no PR needed, path-based branch protection -> gates); code changes require the full PR Merge Gate (5 sign-offs). +> time (Step 7). SDD docs use a docs branch + PR targeting `dev` (GitHub branch protection +> applies to the whole branch, so a PR is required); code changes require the full PR Merge Gate (5 sign-offs). ## Config Templates @@ -702,9 +702,9 @@ Ready-to-fill templates are in `references/templates/`: artifact verification, SonarCloud QG check. DevOps reads final pipeline status (1 API call instead of 8+ separate verification calls). - **Step 7 (Release Merge):** PM Agent authorizes (sign-offs + human approval), - developer agent (Backend if both active, otherwise sole developer) creates and merges - the `dev` -> `main` PR via GitHub MCP. Simplified conflict resolution: default - "prefer dev" strategy (4 steps), full domain-owner resolution only if CI/CD fails. + developer agent (Backend if both active, otherwise sole developer) creates and merges + the `dev` -> `main` PR via GitHub MCP. Conflict resolution uses domain-owner strategy + (each agent resolves its own files; do NOT blanket-accept dev for all files). - **Step 8 (Deployment):** PM Agent authorizes (human approval), DevOps Agent executes (SSH into Huawei Cloud ECS, docker pull, docker run, health check, rollback on failure). diff --git a/skills/sdlc-agentic-pipeline/references/templates/add_ssh_key.py b/skills/sdlc-agentic-pipeline/references/templates/add_ssh_key.py index 7eb9418..1a53b52 100644 --- a/skills/sdlc-agentic-pipeline/references/templates/add_ssh_key.py +++ b/skills/sdlc-agentic-pipeline/references/templates/add_ssh_key.py @@ -19,7 +19,7 @@ def add_ssh_key(): except paramiko.SSHException as e: print(f"ERROR: Host key verification failed for {ECS_HOST}.") print(f"Verify the ECS host fingerprint first: ssh-keyscan {ECS_HOST} >> {KNOWN_HOSTS_PATH}") - print(f"Then re-run this script.") + print("Then re-run this script.") sys.exit(1) pub_key_path = os.path.expanduser("~/.ssh/id_rsa.pub") diff --git a/skills/sdlc-agentic-pipeline/references/templates/ci-cd.yml b/skills/sdlc-agentic-pipeline/references/templates/ci-cd.yml index 35c9930..5ed9a18 100644 --- a/skills/sdlc-agentic-pipeline/references/templates/ci-cd.yml +++ b/skills/sdlc-agentic-pipeline/references/templates/ci-cd.yml @@ -1,13 +1,13 @@ # CI/CD Pipeline Template # -# Flow: build -> sonar-scan -> sonar-qg-check -> deploy-to-jfrog -> verify-jfrog +# Flow: build -> sonar-scan -> deploy-to-jfrog -> verify-jfrog # # Stage order rationale (prevents resource waste and faulty code deployment): -# 1. build - Install deps, verify code compiles (fail fast) -# 2. sonar-scan - Run tests with coverage + SonarCloud analysis -# 3. sonar-qg-check - Quality Gate check (BLOCK deploy if QG fails) -# 4. deploy-to-jfrog - Docker build + push to JFrog (only if QG passes) -# 5. verify-jfrog - Verify artifact exists in JFrog +# 1. build - Install deps, verify code compiles (fail fast) +# 2. sonar-scan - Run tests with coverage + SonarCloud analysis + QG check +# (sonar.qualitygate.wait=true blocks until QG passes/fails) +# 3. deploy-to-jfrog - Docker build + push to JFrog (only if QG passes) +# 4. verify-jfrog - Verify artifact exists in JFrog # # AUTO-TRIGGERED on push to dev branch (no manual trigger needed). # Also supports manual workflow_dispatch trigger. @@ -148,28 +148,9 @@ jobs: with: args: -Dsonar.qualitygate.wait=true - sonar-qg-check: - needs: - - sonar-scan - - runs-on: ubuntu-latest - - steps: - - name: Check SonarCloud Quality Gate - run: | - QG_STATUS=$(curl -s -u "${{ secrets.SONAR_TOKEN }}:" \ - "https://sonarcloud.io/api/qualitygates/project_status?projectKey=${{ vars.SONAR_PROJECT_KEY }}" \ - | jq -r '.projectStatus.status') - if [ "$QG_STATUS" != "OK" ]; then - echo "ERROR: SonarCloud Quality Gate FAILED ($QG_STATUS)" - echo "Docker image will NOT be built or pushed to JFrog" - exit 1 - fi - echo "SonarCloud Quality Gate PASSED - proceeding to deploy" - deploy-to-jfrog: needs: - - sonar-qg-check + - sonar-scan runs-on: ubuntu-latest