From 751a2811188056cdf39c8376458aabf66b322e1a Mon Sep 17 00:00:00 2001 From: ankitjangir1690 Date: Sun, 30 Nov 2025 18:39:52 +0530 Subject: [PATCH 01/16] feat: adding project in workflow --- .github/workflows/add-pr-to-devops.yml | 22 ++++++++++++++++++++++ .github/workflows/auto-reviewer.yml | 7 ++++--- .github/workflows/bot-handler.yml | 3 ++- 3 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/add-pr-to-devops.yml diff --git a/.github/workflows/add-pr-to-devops.yml b/.github/workflows/add-pr-to-devops.yml new file mode 100644 index 0000000..7971603 --- /dev/null +++ b/.github/workflows/add-pr-to-devops.yml @@ -0,0 +1,22 @@ +name: Add PR to DevOps Board + +on: + pull_request: + types: [opened, reopened] + branches: [master] + push: + branches: [master] + +jobs: + add_to_project: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + steps: + - name: Add PR to DevOps Release Board + uses: actions/add-to-project@v0.5.0 + with: + project-url: https://github.com/orgs/dhwani-ris/projects/## + github-token: ${{ secrets.GITHUB_TOKEN }} + diff --git a/.github/workflows/auto-reviewer.yml b/.github/workflows/auto-reviewer.yml index 5ba1e01..f97e436 100644 --- a/.github/workflows/auto-reviewer.yml +++ b/.github/workflows/auto-reviewer.yml @@ -2,7 +2,8 @@ name: Auto Request Review on: pull_request: - types: [opened, synchronize, reopened, ready_for_review] + types: [opened, synchronize, reopened, ready_for_review, closed] + branches: [master] permissions: pull-requests: write @@ -13,8 +14,8 @@ jobs: name: Request Review from Default Reviewer runs-on: ubuntu-latest if: | - github.event.pull_request.base.ref == 'main' || - github.event.pull_request.base.ref == 'master' + (github.event.action == 'opened' || github.event.action == 'reopened' || github.event.action == 'synchronize' || github.event.action == 'ready_for_review') && + (github.event.pull_request.base.ref == 'main' || github.event.pull_request.base.ref == 'master') steps: - name: Request review from default reviewer diff --git a/.github/workflows/bot-handler.yml b/.github/workflows/bot-handler.yml index 8b0476a..050c0ed 100644 --- a/.github/workflows/bot-handler.yml +++ b/.github/workflows/bot-handler.yml @@ -4,7 +4,8 @@ on: issue_comment: types: [created, edited] pull_request: - types: [opened, synchronize, reopened] + types: [opened, synchronize, reopened, closed] + branches: [master] permissions: contents: write From b02880aa958f81bc6895bebe1618567343da9e05 Mon Sep 17 00:00:00 2001 From: ankitjangir1690 Date: Sun, 30 Nov 2025 18:51:54 +0530 Subject: [PATCH 02/16] fix: updated the deployment note and devops checklist --- .github/workflows/add-pr-to-devops.yml | 9 +- .github/workflows/devops-checklist.yml | 132 +++++-------------------- 2 files changed, 30 insertions(+), 111 deletions(-) diff --git a/.github/workflows/add-pr-to-devops.yml b/.github/workflows/add-pr-to-devops.yml index 7971603..08b6733 100644 --- a/.github/workflows/add-pr-to-devops.yml +++ b/.github/workflows/add-pr-to-devops.yml @@ -3,16 +3,19 @@ name: Add PR to DevOps Board on: pull_request: types: [opened, reopened] - branches: [master] - push: - branches: [master] + branches: [main, master] jobs: add_to_project: runs-on: ubuntu-latest + if: | + github.event.pull_request.base.ref == 'main' || + github.event.pull_request.base.ref == 'master' permissions: contents: read pull-requests: write + repository-projects: write + organization-projects: write steps: - name: Add PR to DevOps Release Board uses: actions/add-to-project@v0.5.0 diff --git a/.github/workflows/devops-checklist.yml b/.github/workflows/devops-checklist.yml index 1bc8956..6efce84 100644 --- a/.github/workflows/devops-checklist.yml +++ b/.github/workflows/devops-checklist.yml @@ -181,87 +181,6 @@ jobs: |-------|-----------------|----------------|-----------------| | 1. | \`${context.repo.repo}\` | \`${pr.base.ref}-release-${version}\` | ${formatFeatureDetails(featureDetails)} | - **Dependencies:** - - Dependencies updated: \`TBD\` *(Please review and update)* - \`\`\` - - \`\`\` - - **Database Changes (Queries to run):** - - Database changes required: \`TBD\` *(Please review and update)* - \`\`\` - - \`\`\` - - **Testing:** - - [ ] Unit tests passed - - [ ] Integration tests passed - - [ ] E2E tests passed - - [ ] Manual testing completed - \`\`\` - - \`\`\` - - **Known Issues:** - - Known issues: \`TBD\` *(Please review and update)* - \`\`\` - - \`\`\` - - **Contact Information:** - - Support Team Email: \`\`\`\`\`\` - - Support Team Phone: \`\`\`\`\`\` - - **Attachments:** - - Deployment files attached/committed: \`TBD\` *(Please review and update)* - \`\`\` - - \`\`\` - - --- - - ### For DevOps Team Use Only - *(To be filled by the DevOps team after deploying the release)* - - **Deployment Details:** - - Date and time of deployment: \`\`\`\`\`\` - - Deployed by: \`\`\`\`\`\` - - Deployment Status: \`\`\`\`\`\` - - **Deployment Instructions:** - - [ ] Pre-deployment tasks completed (backups, etc.) - - [ ] Production environment accessed securely - - [ ] Latest release pulled from version control - - [ ] Dependencies installed/updated - - [ ] Database migrations run (if applicable) - - [ ] Application services restarted - - [ ] Deployment monitored and verified - - **Rollback Plan:** - - [ ] Rollback procedure documented - - [ ] Previous version tag identified: \`\`\`\`\`\` - - [ ] Database rollback scripts prepared (if applicable) - - [ ] Rollback tested in staging environment - - **Post-Deployment Checklist:** - - [ ] Service availability and response times verified - - [ ] System resources monitored - - [ ] Critical user scenarios tested - - [ ] Data integrity confirmed - - [ ] Error logs reviewed - - [ ] Security scans completed - - [ ] Server and infrastructure health checked - - [ ] Backup and disaster recovery procedures validated - - **Notes:** - \`\`\` - - \`\`\` - - **Acknowledgment:** - - [ ] Deployment acknowledged and system ready for production use - - --- **Note:** This deployment document was **automatically generated** from PR commits and information. Please review and update the TBD sections before merging.`; // Check if comment already exists @@ -320,6 +239,26 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const pr = context.payload.pull_request; + + // Check if comment already exists + const comments = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr.number, + }); + + const existingComment = comments.data.find( + comment => comment.user.type === 'Bot' && + comment.body.includes('DevOps Checklist - Workflow Review') + ); + + if (existingComment) { + // Don't update existing comment to preserve checkbox states + console.log('DevOps Checklist comment already exists, preserving user checkboxes'); + return; + } + + // Only create new comment if it doesn't exist const checklist = `## 🔧 DevOps Checklist - Workflow Review **Please review all workflows and checks before merging:** @@ -350,35 +289,12 @@ jobs: --- **Note:** This checklist is for DevOps team to verify all workflows and checks before merging.`; - // Check if comment already exists - const comments = await github.rest.issues.listComments({ + // Create new comment + await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: pr.number, + body: checklist }); - - const existingComment = comments.data.find( - comment => comment.user.type === 'Bot' && - comment.body.includes('DevOps Checklist - Workflow Review') - ); - - if (existingComment) { - // Update existing comment - await github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: existingComment.id, - body: checklist - }); - console.log('Updated existing DevOps Checklist comment'); - } else { - // Create new comment - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: pr.number, - body: checklist - }); - console.log('Created new DevOps Checklist comment'); - } + console.log('Created new DevOps Checklist comment'); From 66d8889a1d3c29cd62b25fad7f22f576862ec826 Mon Sep 17 00:00:00 2001 From: ankitjangir1690 Date: Sun, 30 Nov 2025 19:34:16 +0530 Subject: [PATCH 03/16] fix: updated the devops checklist and correct the checklist submission --- .github/workflows/devops-checklist-submit.yml | 124 ++++++++++++++++++ .github/workflows/devops-checklist.yml | 96 ++++++++++---- 2 files changed, 197 insertions(+), 23 deletions(-) create mode 100644 .github/workflows/devops-checklist-submit.yml diff --git a/.github/workflows/devops-checklist-submit.yml b/.github/workflows/devops-checklist-submit.yml new file mode 100644 index 0000000..33d700d --- /dev/null +++ b/.github/workflows/devops-checklist-submit.yml @@ -0,0 +1,124 @@ +name: DevOps Checklist Submission + +on: + issue_comment: + types: [created] + +permissions: + pull-requests: write + contents: read + +jobs: + submit-checklist: + runs-on: ubuntu-latest + if: | + github.event.issue.pull_request && + contains(github.event.comment.body, '/submit-checklist') + steps: + - name: Get PR number + id: get-pr + uses: actions/github-script@v8 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const prNumber = context.payload.issue.number; + core.setOutput('pr_number', prNumber); + return prNumber; + + - name: Submit and lock checklist + uses: actions/github-script@v8 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const prNumber = context.payload.issue.number; + const submitter = context.payload.comment.user.login; + const submitTime = new Date().toISOString(); + const submitDate = new Date().toLocaleString('en-US', { + timeZone: 'UTC', + year: 'numeric', + month: 'long', + day: 'numeric', + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + timeZoneName: 'short' + }); + + // Get all comments to find the checklist + const comments = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + }); + + const checklistComment = comments.data.find( + comment => comment.user.type === 'Bot' && + comment.body.includes('DevOps Checklist - Workflow Review') + ); + + if (!checklistComment) { + console.log('Checklist comment not found'); + return; + } + + // Check if already submitted + if (checklistComment.body.includes('✅ **CHECKLIST SUBMITTED**')) { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body: `⚠️ This checklist has already been submitted and cannot be modified.` + }); + return; + } + + // Extract the current checklist content (preserve checkboxes) + let checklistBody = checklistComment.body; + + // Replace the submission section with submitted status + const submittedSection = `--- + + ### ✅ **CHECKLIST SUBMITTED** + + **Submitted by:** @${submitter} + **Submitted at:** ${submitDate} (UTC) + + 🔒 **This checklist is now locked and cannot be modified.** + + --- + **Note:** This checklist was submitted and is final. No further changes can be made.`; + + // Find and replace the submission section + // Look for the "Submit Checklist" section and replace everything from there to the end + const submitSectionStart = checklistBody.indexOf('### 📤 Submit Checklist'); + if (submitSectionStart !== -1) { + // Keep everything before the submission section, then add the submitted section + checklistBody = checklistBody.substring(0, submitSectionStart) + submittedSection; + } else { + // If section not found, append the submitted section + checklistBody = checklistBody + '\n\n' + submittedSection; + } + + // Update the checklist comment to show it's submitted + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: checklistComment.id, + body: checklistBody + }); + + // Add a confirmation comment + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body: `✅ **Checklist submitted successfully!** + + The DevOps Checklist has been locked and cannot be modified. + + **Submitted by:** @${submitter} + **Time:** ${submitDate} (UTC)` + }); + + console.log(`Checklist submitted by ${submitter} at ${submitTime}`); + diff --git a/.github/workflows/devops-checklist.yml b/.github/workflows/devops-checklist.yml index 6efce84..aa6eb8e 100644 --- a/.github/workflows/devops-checklist.yml +++ b/.github/workflows/devops-checklist.yml @@ -253,6 +253,11 @@ jobs: ); if (existingComment) { + // Check if already submitted + if (existingComment.body.includes('✅ **CHECKLIST SUBMITTED**')) { + console.log('Checklist already submitted and locked, cannot update'); + return; + } // Don't update existing comment to preserve checkbox states console.log('DevOps Checklist comment already exists, preserving user checkboxes'); return; @@ -263,31 +268,76 @@ jobs: **Please review all workflows and checks before merging:** - ### Workflow Status Review - - [ ] All CI/CD workflows are passing - - [ ] Quality Checks workflow passed - - [ ] Security Scan workflow passed - - [ ] Code quality checks passed - - [ ] Test coverage meets requirements - - ### Review Status - - [ ] All required reviewers have approved - - [ ] Code review completed - - [ ] Security review completed (if applicable) - - ### Pre-Merge Verification - - [ ] Deployment Notes document reviewed (see Deployment Notes comment above) - - [ ] All commits reviewed - - [ ] Breaking changes identified (if any) - - [ ] Version number verified (if applicable) - - ### Final Checks - - [ ] No blocking issues or errors - - [ ] Ready for production deployment - - [ ] Rollback plan understood (if high-risk) + ### 1. Workflow Status Review + - [ ] DevOps Checklist Reminder + - [ ] Documentation Required + - [ ] Semantic Commits + - [ ] GitHub Actions Security (send-secrets) + - [ ] Quality Checks / Pre-Commit + - [ ] Quality Checks / Semgrep Rules + - [ ] All other workflows passing + + ### 2. Code Review & Approval + - [ ] Team Lead has approved the PR + - [ ] All reviewer comments resolved + - [ ] No leftover debug logs, temp files, zip files, or accidental commits + - [ ] No exposed secrets or credentials + - [ ] Commit messages follow semantic standards + + ### 3. Documentation & Release Notes + - [ ] Deployment Notes reviewed + - [ ] Change summary provided + - [ ] Impacted modules/services listed + - [ ] Config or environment changes documented + - [ ] Rollback Plan attached + - [ ] 🔗 Rollback Reference: https://devops.dhwaniris.com/rollback-guidelines + + ### 4. Functional & QA Validation + - [ ] Changes tested on staging/UAT + - [ ] QA sign-off received + - [ ] No high/critical bugs pending + - [ ] Regression testing completed + - [ ] API responses verified (if applicable) + + ### 5. Security & Compliance + - [ ] Semgrep Rules passed (mandatory) + - [ ] No new security warnings introduced + - [ ] Sensitive logic reviewed + - [ ] No secrets in PR (manual confirmation) + + ### 6. Deployment Verification + - [ ] Deployment strategy identified (Blue/Green / Rolling / Manual) + - [ ] Downtime estimate validated (if applicable) + - [ ] Backup/restore plan ready + - [ ] Monitoring alerts configured or validated + - [ ] Pre-deployment checks completed (DB migrations, queues, cron, cache, etc.) + + ### 7. Merge Validation + - [ ] PR raised from development → master (correct flow) + - [ ] Branch updated with latest master (no conflicts) + - [ ] All merge blockers cleared + - [ ] No pending tasks or approvals + + ### 8. Final DevOps Decision + - [ ] **GO** → Safe to merge into production + - [ ] **NO-GO** → Blocked; failures listed below: + + **Notes:** + \`\`\` + + \`\`\` --- - **Note:** This checklist is for DevOps team to verify all workflows and checks before merging.`; + + ### 📤 Submit Checklist + + **To submit this checklist (cannot be reverted once submitted):** + + Comment: \`/submit-checklist\` + + ⚠️ **Warning:** Once submitted, this checklist will be locked and cannot be modified. + + **Status:** ⏳ *Pending Submission*`; // Create new comment await github.rest.issues.createComment({ From 6b516111be353bc27e591f93a3cad7fb362fff56 Mon Sep 17 00:00:00 2001 From: ankitjangir1690 Date: Sun, 30 Nov 2025 19:41:42 +0530 Subject: [PATCH 04/16] fix: correct the checklist submission --- .github/workflows/devops-checklist-submit.yml | 126 +++++++++++++++++- .github/workflows/devops-checklist.yml | 5 +- 2 files changed, 124 insertions(+), 7 deletions(-) diff --git a/.github/workflows/devops-checklist-submit.yml b/.github/workflows/devops-checklist-submit.yml index 33d700d..89a6820 100644 --- a/.github/workflows/devops-checklist-submit.yml +++ b/.github/workflows/devops-checklist-submit.yml @@ -2,7 +2,9 @@ name: DevOps Checklist Submission on: issue_comment: - types: [created] + types: [created, edited] + pull_request: + types: [synchronize, reopened, ready_for_review, closed] permissions: pull-requests: write @@ -12,8 +14,8 @@ jobs: submit-checklist: runs-on: ubuntu-latest if: | - github.event.issue.pull_request && - contains(github.event.comment.body, '/submit-checklist') + (github.event_name == 'issue_comment' && github.event.issue.pull_request && contains(github.event.comment.body, '/submit-checklist')) || + (github.event_name == 'pull_request' && (github.event.action == 'synchronize' || github.event.action == 'reopened' || github.event.action == 'ready_for_review' || github.event.action == 'closed')) steps: - name: Get PR number id: get-pr @@ -26,6 +28,7 @@ jobs: return prNumber; - name: Submit and lock checklist + if: github.event_name == 'issue_comment' && contains(github.event.comment.body, '/submit-checklist') uses: actions/github-script@v8 with: github-token: ${{ secrets.GITHUB_TOKEN }} @@ -75,16 +78,21 @@ jobs: // Extract the current checklist content (preserve checkboxes) let checklistBody = checklistComment.body; + // Extract submission info to preserve it + const submissionInfo = `**Submitted by:** @${submitter} + **Submitted at:** ${submitDate} (UTC)`; + // Replace the submission section with submitted status const submittedSection = `--- ### ✅ **CHECKLIST SUBMITTED** - **Submitted by:** @${submitter} - **Submitted at:** ${submitDate} (UTC) + ${submissionInfo} 🔒 **This checklist is now locked and cannot be modified.** + + --- **Note:** This checklist was submitted and is final. No further changes can be made.`; @@ -121,4 +129,112 @@ jobs: }); console.log(`Checklist submitted by ${submitter} at ${submitTime}`); + + - name: Re-lock checklist if edited after submission + if: | + (github.event_name == 'issue_comment' && github.event.action == 'edited') || + (github.event_name == 'pull_request') + uses: actions/github-script@v8 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const prNumber = github.event_name == 'issue_comment' + ? context.payload.issue.number + : context.payload.pull_request.number; + + // Get all comments to find the checklist + const comments = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + }); + + const checklistComment = comments.data.find( + comment => comment.user.type === 'Bot' && + comment.body.includes('DevOps Checklist - Workflow Review') + ); + + if (!checklistComment) { + return; + } + + // Check if checklist was previously submitted (look for submission marker) + const hasSubmissionMarker = checklistComment.body.includes('CHECKLIST_SUBMITTED_LOCK'); + const hasSubmittedText = checklistComment.body.includes('✅ **CHECKLIST SUBMITTED**'); + + // If it was submitted, ensure it's locked + if (hasSubmissionMarker || hasSubmittedText) { + let checklistBody = checklistComment.body; + + // Extract submission info + const submitterMatch = checklistBody.match(/\*\*Submitted by:\*\* @(\S+)/); + const dateMatch = checklistBody.match(/\*\*Submitted at:\*\* (.+?)(?:\n|UTC)/); + const submitter = submitterMatch ? submitterMatch[1] : 'System'; + const submitDate = dateMatch ? dateMatch[1].trim() : new Date().toLocaleString('en-US', { + timeZone: 'UTC', + year: 'numeric', + month: 'long', + day: 'numeric', + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + timeZoneName: 'short' + }); + + // Check if lock section is present and complete + const hasLockMessage = checklistBody.includes('🔒 **This checklist is now locked and cannot be modified.**'); + const hasCompleteLock = hasSubmittedText && hasLockMessage; + + // If lock is missing or incomplete, restore it + if (!hasCompleteLock) { + // Find where to insert/update the lock section + const submitIndex = checklistBody.indexOf('### ✅ **CHECKLIST SUBMITTED**'); + const lockSection = `--- + + ### ✅ **CHECKLIST SUBMITTED** + + **Submitted by:** @${submitter} + **Submitted at:** ${submitDate} (UTC) + + 🔒 **This checklist is now locked and cannot be modified.** + + + + --- + **Note:** This checklist was submitted and is final. No further changes can be made.`; + + if (submitIndex !== -1) { + // Replace from submission header to end of comment + const beforeSubmit = checklistBody.substring(0, submitIndex); + checklistBody = beforeSubmit + lockSection; + } else { + // Append lock section if submission header is missing + checklistBody = checklistBody + '\n\n' + lockSection; + } + + // Re-lock the checklist + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: checklistComment.id, + body: checklistBody + }); + + // Add a warning comment only if this is an edit event (not PR sync) + if (github.event_name == 'issue_comment' && github.event.action == 'edited') { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body: `⚠️ **Checklist Re-locked** + + The DevOps Checklist was modified after submission. It has been automatically re-locked. + + 🔒 **This checklist cannot be modified once submitted.**` + }); + } + + console.log('Checklist re-locked after unauthorized edit'); + } + } diff --git a/.github/workflows/devops-checklist.yml b/.github/workflows/devops-checklist.yml index aa6eb8e..0ea9a0a 100644 --- a/.github/workflows/devops-checklist.yml +++ b/.github/workflows/devops-checklist.yml @@ -253,8 +253,9 @@ jobs: ); if (existingComment) { - // Check if already submitted - if (existingComment.body.includes('✅ **CHECKLIST SUBMITTED**')) { + // Check if already submitted (check both visible marker and hidden marker) + if (existingComment.body.includes('✅ **CHECKLIST SUBMITTED**') || + existingComment.body.includes('CHECKLIST_SUBMITTED_LOCK')) { console.log('Checklist already submitted and locked, cannot update'); return; } From 0b4e21d947f390cec77b6b3390f5467839bab37f Mon Sep 17 00:00:00 2001 From: ankitjangir1690 Date: Sun, 30 Nov 2025 19:52:01 +0530 Subject: [PATCH 05/16] fix: correct the checklist submission --- .github/workflows/devops-checklist-submit.yml | 97 +++++++++++++++- .github/workflows/devops-checklist.yml | 105 ++++++------------ 2 files changed, 126 insertions(+), 76 deletions(-) diff --git a/.github/workflows/devops-checklist-submit.yml b/.github/workflows/devops-checklist-submit.yml index 89a6820..0630c26 100644 --- a/.github/workflows/devops-checklist-submit.yml +++ b/.github/workflows/devops-checklist-submit.yml @@ -107,6 +107,20 @@ jobs: checklistBody = checklistBody + '\n\n' + submittedSection; } + // Extract and store the exact checkbox states before locking + const checkboxStates = []; + const checkboxRegex = /- \[([ x])\] (.+)/g; + let match; + while ((match = checkboxRegex.exec(checklistBody)) !== null) { + checkboxStates.push({ + checked: match[1] === 'x', + text: match[2] + }); + } + + // Store checkbox states in a hidden comment for restoration + const checkboxStatesJson = JSON.stringify(checkboxStates); + // Update the checklist comment to show it's submitted await github.rest.issues.updateComment({ owner: context.repo.owner, @@ -115,6 +129,43 @@ jobs: body: checklistBody }); + // Add a hidden comment with checkbox states for restoration + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body: `` + }); + + // Add label to track submission + try { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + labels: ['devops-checklist-submitted'] + }); + } catch (e) { + // Label might not exist, create it + try { + await github.rest.issues.createLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + name: 'devops-checklist-submitted', + color: '28a745', + description: 'DevOps Checklist has been submitted and locked' + }); + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + labels: ['devops-checklist-submitted'] + }); + } catch (labelError) { + console.log('Could not create/add label:', labelError.message); + } + } + // Add a confirmation comment await github.rest.issues.createComment({ owner: context.repo.owner, @@ -162,10 +213,27 @@ jobs: const hasSubmissionMarker = checklistComment.body.includes('CHECKLIST_SUBMITTED_LOCK'); const hasSubmittedText = checklistComment.body.includes('✅ **CHECKLIST SUBMITTED**'); - // If it was submitted, ensure it's locked + // If it was submitted, ensure it's locked and restore checkbox states if (hasSubmissionMarker || hasSubmittedText) { let checklistBody = checklistComment.body; + // Get stored checkbox states from hidden comment + let storedStates = null; + const allComments = comments.data; + for (const comment of allComments) { + if (comment.body.includes('CHECKLIST_STATES:')) { + const statesMatch = comment.body.match(/CHECKLIST_STATES:(.+)/); + if (statesMatch) { + try { + storedStates = JSON.parse(statesMatch[1]); + break; + } catch (e) { + console.log('Could not parse stored states'); + } + } + } + } + // Extract submission info const submitterMatch = checklistBody.match(/\*\*Submitted by:\*\* @(\S+)/); const dateMatch = checklistBody.match(/\*\*Submitted at:\*\* (.+?)(?:\n|UTC)/); @@ -181,12 +249,31 @@ jobs: timeZoneName: 'short' }); + // Restore checkbox states if we have stored states + if (storedStates && storedStates.length > 0) { + let restoredBody = checklistBody; + const checkboxRegex = /- \[([ x])\] (.+)/g; + let stateIndex = 0; + + restoredBody = restoredBody.replace(checkboxRegex, (match, checked, text) => { + if (stateIndex < storedStates.length) { + const state = storedStates[stateIndex]; + stateIndex++; + // Restore the original checkbox state + return `- [${state.checked ? 'x' : ' '}] ${state.text}`; + } + return match; + }); + + checklistBody = restoredBody; + } + // Check if lock section is present and complete const hasLockMessage = checklistBody.includes('🔒 **This checklist is now locked and cannot be modified.**'); const hasCompleteLock = hasSubmittedText && hasLockMessage; - // If lock is missing or incomplete, restore it - if (!hasCompleteLock) { + // If lock is missing or incomplete, or checkboxes were changed, restore it + if (!hasCompleteLock || (storedStates && checklistBody !== checklistComment.body)) { // Find where to insert/update the lock section const submitIndex = checklistBody.indexOf('### ✅ **CHECKLIST SUBMITTED**'); const lockSection = `--- @@ -212,7 +299,7 @@ jobs: checklistBody = checklistBody + '\n\n' + lockSection; } - // Re-lock the checklist + // Re-lock the checklist with restored states await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, @@ -228,7 +315,7 @@ jobs: issue_number: prNumber, body: `⚠️ **Checklist Re-locked** - The DevOps Checklist was modified after submission. It has been automatically re-locked. + The DevOps Checklist was modified after submission. It has been automatically re-locked and restored to its submitted state. 🔒 **This checklist cannot be modified once submitted.**` }); diff --git a/.github/workflows/devops-checklist.yml b/.github/workflows/devops-checklist.yml index 0ea9a0a..f65a085 100644 --- a/.github/workflows/devops-checklist.yml +++ b/.github/workflows/devops-checklist.yml @@ -137,22 +137,22 @@ jobs: const fixes = commits.filter(c => c.message.startsWith('fix')).map(c => c.message.replace(/^fix(\(.+?\))?:\s*/i, '')); const other = commits.filter(c => !c.message.startsWith('feat') && !c.message.startsWith('fix') && !c.message.startsWith('chore') && !c.message.startsWith('ci')); - // Build feature details + // Build feature details (without numbering - will be added in formatFeatureDetails) let featureDetails = []; if (features.length > 0) { - featureDetails.push(...features.map(f => `1) ${f}`)); + featureDetails.push(...features); } if (fixes.length > 0) { - featureDetails.push(...fixes.map(f => `2) ${f}`)); + featureDetails.push(...fixes); } if (other.length > 0) { - featureDetails.push(...other.slice(0, 5).map((o, i) => `${i + 3}) ${o.message}`)); + featureDetails.push(...other.slice(0, 5).map(o => o.message)); } const today = new Date().toISOString().split('T')[0]; const releaseDate = today.split('-').reverse().join('-'); // Format: DD-MM-YYYY - // Format feature details better + // Format feature details with sequential numbering const formatFeatureDetails = (details) => { if (details.length === 0) return 'See commits above'; return details.map((f, i) => `${i + 1}) ${f}`).join('
'); @@ -265,80 +265,43 @@ jobs: } // Only create new comment if it doesn't exist - const checklist = `## 🔧 DevOps Checklist - Workflow Review - - **Please review all workflows and checks before merging:** - - ### 1. Workflow Status Review - - [ ] DevOps Checklist Reminder - - [ ] Documentation Required - - [ ] Semantic Commits - - [ ] GitHub Actions Security (send-secrets) - - [ ] Quality Checks / Pre-Commit - - [ ] Quality Checks / Semgrep Rules - - [ ] All other workflows passing - - ### 2. Code Review & Approval - - [ ] Team Lead has approved the PR - - [ ] All reviewer comments resolved - - [ ] No leftover debug logs, temp files, zip files, or accidental commits - - [ ] No exposed secrets or credentials - - [ ] Commit messages follow semantic standards - - ### 3. Documentation & Release Notes - - [ ] Deployment Notes reviewed - - [ ] Change summary provided - - [ ] Impacted modules/services listed - - [ ] Config or environment changes documented - - [ ] Rollback Plan attached - - [ ] 🔗 Rollback Reference: https://devops.dhwaniris.com/rollback-guidelines - - ### 4. Functional & QA Validation - - [ ] Changes tested on staging/UAT - - [ ] QA sign-off received - - [ ] No high/critical bugs pending - - [ ] Regression testing completed - - [ ] API responses verified (if applicable) - - ### 5. Security & Compliance - - [ ] Semgrep Rules passed (mandatory) - - [ ] No new security warnings introduced - - [ ] Sensitive logic reviewed - - [ ] No secrets in PR (manual confirmation) - - ### 6. Deployment Verification - - [ ] Deployment strategy identified (Blue/Green / Rolling / Manual) - - [ ] Downtime estimate validated (if applicable) - - [ ] Backup/restore plan ready - - [ ] Monitoring alerts configured or validated - - [ ] Pre-deployment checks completed (DB migrations, queues, cron, cache, etc.) - - ### 7. Merge Validation - - [ ] PR raised from development → master (correct flow) - - [ ] Branch updated with latest master (no conflicts) - - [ ] All merge blockers cleared - - [ ] No pending tasks or approvals - - ### 8. Final DevOps Decision - - [ ] **GO** → Safe to merge into production - - [ ] **NO-GO** → Blocked; failures listed below: + const checklist = `## 🔧 DevOps Checklist + + ### Workflows & Quality + - [ ] All CI/CD workflows passing + - [ ] Code quality checks passed + - [ ] Security scans passed + - [ ] No secrets or credentials exposed + + ### Review & Testing + - [ ] Code review approved + - [ ] Tested on staging/UAT + - [ ] No critical bugs pending + + ### Documentation + - [ ] Deployment notes reviewed + - [ ] Rollback plan documented + - [ ] 🔗 [Rollback Guidelines](https://devops.dhwaniris.com/rollback-guidelines) + + ### Deployment Readiness + - [ ] DB migrations ready (if applicable) + - [ ] Config changes documented + - [ ] Monitoring alerts validated + + ### Final Decision + - [ ] **GO** - Ready for production + - [ ] **NO-GO** - Blocked (see notes) **Notes:** \`\`\` - + \`\`\` --- - ### 📤 Submit Checklist - - **To submit this checklist (cannot be reverted once submitted):** - - Comment: \`/submit-checklist\` - - ⚠️ **Warning:** Once submitted, this checklist will be locked and cannot be modified. + **Submit:** Comment \`/submit-checklist\` to lock this checklist - **Status:** ⏳ *Pending Submission*`; + ⚠️ Once submitted, this checklist cannot be modified.`; // Create new comment await github.rest.issues.createComment({ From c9980138565d0d87c2edc2ecf557e6c0d4d55845 Mon Sep 17 00:00:00 2001 From: ankitjangir1690 Date: Sun, 30 Nov 2025 20:01:08 +0530 Subject: [PATCH 06/16] fix: added more fixes --- .../devops-checklist-lock-monitor.yml | 175 ++++++++++++++++++ .github/workflows/devops-checklist-submit.yml | 4 +- 2 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/devops-checklist-lock-monitor.yml diff --git a/.github/workflows/devops-checklist-lock-monitor.yml b/.github/workflows/devops-checklist-lock-monitor.yml new file mode 100644 index 0000000..8ddf443 --- /dev/null +++ b/.github/workflows/devops-checklist-lock-monitor.yml @@ -0,0 +1,175 @@ +name: DevOps Checklist Lock Monitor + +on: + schedule: + # Run every 5 minutes to check and re-lock submitted checklists + - cron: '*/5 * * * *' + workflow_dispatch: + pull_request: + types: [synchronize, reopened, ready_for_review, edited] + issue_comment: + types: [created, edited] + +permissions: + pull-requests: write + contents: read + +jobs: + monitor-and-relock: + runs-on: ubuntu-latest + steps: + - name: Monitor and re-lock submitted checklists + uses: actions/github-script@v8 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const repo = context.repo; + let prNumbers = []; + + // If triggered by PR event, check that specific PR + if (context.eventName === 'pull_request') { + prNumbers = [context.payload.pull_request.number]; + } else if (context.eventName === 'issue_comment' && context.payload.issue.pull_request) { + prNumbers = [context.payload.issue.number]; + } else { + // For scheduled runs, get all open PRs targeting main/master + const { data: prs } = await github.rest.pulls.list({ + owner: repo.owner, + repo: repo.repo, + state: 'open', + base: 'main', + per_page: 50 + }); + + const { data: masterPRs } = await github.rest.pulls.list({ + owner: repo.owner, + repo: repo.repo, + state: 'open', + base: 'master', + per_page: 50 + }); + + prNumbers = [...prs.map(p => p.number), ...masterPRs.map(p => p.number)]; + } + + for (const prNumber of prNumbers) { + try { + // Get all comments + const { data: comments } = await github.rest.issues.listComments({ + owner: repo.owner, + repo: repo.repo, + issue_number: prNumber, + }); + + // Find checklist comment + const checklistComment = comments.find( + comment => comment.user.type === 'Bot' && + comment.body.includes('DevOps Checklist') + ); + + if (!checklistComment) continue; + + // Check if submitted + const isSubmitted = checklistComment.body.includes('CHECKLIST_SUBMITTED_LOCK') || + checklistComment.body.includes('✅ **CHECKLIST SUBMITTED**'); + + if (!isSubmitted) continue; + + // Get stored checkbox states + let storedStates = null; + for (const comment of comments) { + if (comment.body.includes('CHECKLIST_STATES:')) { + const match = comment.body.match(/CHECKLIST_STATES:(.+)/); + if (match) { + try { + storedStates = JSON.parse(match[1]); + break; + } catch (e) { + console.log('Could not parse stored states'); + } + } + } + } + + let checklistBody = checklistComment.body; + let needsUpdate = false; + + // Restore checkbox states if we have stored states + if (storedStates && storedStates.length > 0) { + const checkboxRegex = /- \[([ x])\] (.+)/g; + let stateIndex = 0; + let restoredBody = checklistBody; + + restoredBody = restoredBody.replace(checkboxRegex, (match, checked, text) => { + if (stateIndex < storedStates.length) { + const state = storedStates[stateIndex]; + stateIndex++; + const expectedState = state.checked ? 'x' : ' '; + if (checked !== expectedState || text.trim() !== state.text.trim()) { + needsUpdate = true; + return `- [${expectedState}] ${state.text}`; + } + } + return match; + }); + + if (needsUpdate) { + checklistBody = restoredBody; + } + } + + // Ensure lock section is present + if (!checklistBody.includes('🔒 **This checklist is now locked and cannot be modified.**')) { + needsUpdate = true; + const submitterMatch = checklistBody.match(/\*\*Submitted by:\*\* @(\S+)/); + const dateMatch = checklistBody.match(/\*\*Submitted at:\*\* (.+?)(?:\n|UTC)/); + const submitter = submitterMatch ? submitterMatch[1] : 'System'; + const submitDate = dateMatch ? dateMatch[1].trim() : new Date().toLocaleString('en-US', { + timeZone: 'UTC', + year: 'numeric', + month: 'long', + day: 'numeric', + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + timeZoneName: 'short' + }); + + const lockSection = `--- + + ### ✅ **CHECKLIST SUBMITTED** + + **Submitted by:** @${submitter} + **Submitted at:** ${submitDate} (UTC) + + 🔒 **This checklist is now locked and cannot be modified.** + + + + --- + **Note:** This checklist was submitted and is final. No further changes can be made.`; + + const submitIndex = checklistBody.indexOf('### ✅ **CHECKLIST SUBMITTED**'); + if (submitIndex !== -1) { + checklistBody = checklistBody.substring(0, submitIndex) + lockSection; + } else { + checklistBody = checklistBody + '\n\n' + lockSection; + } + } + + // Update if needed + if (needsUpdate) { + await github.rest.issues.updateComment({ + owner: repo.owner, + repo: repo.repo, + comment_id: checklistComment.id, + body: checklistBody + }); + + console.log(`Re-locked checklist for PR #${prNumber}`); + } + } catch (error) { + console.log(`Error processing PR #${prNumber}:`, error.message); + } + } + diff --git a/.github/workflows/devops-checklist-submit.yml b/.github/workflows/devops-checklist-submit.yml index 0630c26..da2aad3 100644 --- a/.github/workflows/devops-checklist-submit.yml +++ b/.github/workflows/devops-checklist-submit.yml @@ -56,7 +56,7 @@ jobs: const checklistComment = comments.data.find( comment => comment.user.type === 'Bot' && - comment.body.includes('DevOps Checklist - Workflow Review') + comment.body.includes('DevOps Checklist') ); if (!checklistComment) { @@ -202,7 +202,7 @@ jobs: const checklistComment = comments.data.find( comment => comment.user.type === 'Bot' && - comment.body.includes('DevOps Checklist - Workflow Review') + comment.body.includes('DevOps Checklist') ); if (!checklistComment) { From 775afa96a73c4fa393011c543000df81eefb4ddf Mon Sep 17 00:00:00 2001 From: ankitjangir1690 Date: Sun, 30 Nov 2025 20:08:39 +0530 Subject: [PATCH 07/16] fix: adding quote reply for checklist --- .github/workflows/devops-checklist-submit.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/devops-checklist-submit.yml b/.github/workflows/devops-checklist-submit.yml index da2aad3..ed2e5db 100644 --- a/.github/workflows/devops-checklist-submit.yml +++ b/.github/workflows/devops-checklist-submit.yml @@ -33,6 +33,13 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | + // Check if the command is present (works with quote replies too) + const commentBody = context.payload.comment.body || ''; + if (!commentBody.includes('/submit-checklist')) { + console.log('Submit command not found in comment'); + return; + } + const prNumber = context.payload.issue.number; const submitter = context.payload.comment.user.login; const submitTime = new Date().toISOString(); From b35e14ea0e4b53d960dea4da75b79f6f0a9ee269 Mon Sep 17 00:00:00 2001 From: ankitjangir1690 Date: Sun, 30 Nov 2025 20:17:21 +0530 Subject: [PATCH 08/16] feat: changing checklist strategy --- .../devops-checklist-lock-monitor.yml | 175 --------- .github/workflows/devops-checklist-submit.yml | 334 ------------------ .github/workflows/devops-checklist.yml | 20 +- 3 files changed, 13 insertions(+), 516 deletions(-) delete mode 100644 .github/workflows/devops-checklist-lock-monitor.yml delete mode 100644 .github/workflows/devops-checklist-submit.yml diff --git a/.github/workflows/devops-checklist-lock-monitor.yml b/.github/workflows/devops-checklist-lock-monitor.yml deleted file mode 100644 index 8ddf443..0000000 --- a/.github/workflows/devops-checklist-lock-monitor.yml +++ /dev/null @@ -1,175 +0,0 @@ -name: DevOps Checklist Lock Monitor - -on: - schedule: - # Run every 5 minutes to check and re-lock submitted checklists - - cron: '*/5 * * * *' - workflow_dispatch: - pull_request: - types: [synchronize, reopened, ready_for_review, edited] - issue_comment: - types: [created, edited] - -permissions: - pull-requests: write - contents: read - -jobs: - monitor-and-relock: - runs-on: ubuntu-latest - steps: - - name: Monitor and re-lock submitted checklists - uses: actions/github-script@v8 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const repo = context.repo; - let prNumbers = []; - - // If triggered by PR event, check that specific PR - if (context.eventName === 'pull_request') { - prNumbers = [context.payload.pull_request.number]; - } else if (context.eventName === 'issue_comment' && context.payload.issue.pull_request) { - prNumbers = [context.payload.issue.number]; - } else { - // For scheduled runs, get all open PRs targeting main/master - const { data: prs } = await github.rest.pulls.list({ - owner: repo.owner, - repo: repo.repo, - state: 'open', - base: 'main', - per_page: 50 - }); - - const { data: masterPRs } = await github.rest.pulls.list({ - owner: repo.owner, - repo: repo.repo, - state: 'open', - base: 'master', - per_page: 50 - }); - - prNumbers = [...prs.map(p => p.number), ...masterPRs.map(p => p.number)]; - } - - for (const prNumber of prNumbers) { - try { - // Get all comments - const { data: comments } = await github.rest.issues.listComments({ - owner: repo.owner, - repo: repo.repo, - issue_number: prNumber, - }); - - // Find checklist comment - const checklistComment = comments.find( - comment => comment.user.type === 'Bot' && - comment.body.includes('DevOps Checklist') - ); - - if (!checklistComment) continue; - - // Check if submitted - const isSubmitted = checklistComment.body.includes('CHECKLIST_SUBMITTED_LOCK') || - checklistComment.body.includes('✅ **CHECKLIST SUBMITTED**'); - - if (!isSubmitted) continue; - - // Get stored checkbox states - let storedStates = null; - for (const comment of comments) { - if (comment.body.includes('CHECKLIST_STATES:')) { - const match = comment.body.match(/CHECKLIST_STATES:(.+)/); - if (match) { - try { - storedStates = JSON.parse(match[1]); - break; - } catch (e) { - console.log('Could not parse stored states'); - } - } - } - } - - let checklistBody = checklistComment.body; - let needsUpdate = false; - - // Restore checkbox states if we have stored states - if (storedStates && storedStates.length > 0) { - const checkboxRegex = /- \[([ x])\] (.+)/g; - let stateIndex = 0; - let restoredBody = checklistBody; - - restoredBody = restoredBody.replace(checkboxRegex, (match, checked, text) => { - if (stateIndex < storedStates.length) { - const state = storedStates[stateIndex]; - stateIndex++; - const expectedState = state.checked ? 'x' : ' '; - if (checked !== expectedState || text.trim() !== state.text.trim()) { - needsUpdate = true; - return `- [${expectedState}] ${state.text}`; - } - } - return match; - }); - - if (needsUpdate) { - checklistBody = restoredBody; - } - } - - // Ensure lock section is present - if (!checklistBody.includes('🔒 **This checklist is now locked and cannot be modified.**')) { - needsUpdate = true; - const submitterMatch = checklistBody.match(/\*\*Submitted by:\*\* @(\S+)/); - const dateMatch = checklistBody.match(/\*\*Submitted at:\*\* (.+?)(?:\n|UTC)/); - const submitter = submitterMatch ? submitterMatch[1] : 'System'; - const submitDate = dateMatch ? dateMatch[1].trim() : new Date().toLocaleString('en-US', { - timeZone: 'UTC', - year: 'numeric', - month: 'long', - day: 'numeric', - hour: '2-digit', - minute: '2-digit', - second: '2-digit', - timeZoneName: 'short' - }); - - const lockSection = `--- - - ### ✅ **CHECKLIST SUBMITTED** - - **Submitted by:** @${submitter} - **Submitted at:** ${submitDate} (UTC) - - 🔒 **This checklist is now locked and cannot be modified.** - - - - --- - **Note:** This checklist was submitted and is final. No further changes can be made.`; - - const submitIndex = checklistBody.indexOf('### ✅ **CHECKLIST SUBMITTED**'); - if (submitIndex !== -1) { - checklistBody = checklistBody.substring(0, submitIndex) + lockSection; - } else { - checklistBody = checklistBody + '\n\n' + lockSection; - } - } - - // Update if needed - if (needsUpdate) { - await github.rest.issues.updateComment({ - owner: repo.owner, - repo: repo.repo, - comment_id: checklistComment.id, - body: checklistBody - }); - - console.log(`Re-locked checklist for PR #${prNumber}`); - } - } catch (error) { - console.log(`Error processing PR #${prNumber}:`, error.message); - } - } - diff --git a/.github/workflows/devops-checklist-submit.yml b/.github/workflows/devops-checklist-submit.yml deleted file mode 100644 index ed2e5db..0000000 --- a/.github/workflows/devops-checklist-submit.yml +++ /dev/null @@ -1,334 +0,0 @@ -name: DevOps Checklist Submission - -on: - issue_comment: - types: [created, edited] - pull_request: - types: [synchronize, reopened, ready_for_review, closed] - -permissions: - pull-requests: write - contents: read - -jobs: - submit-checklist: - runs-on: ubuntu-latest - if: | - (github.event_name == 'issue_comment' && github.event.issue.pull_request && contains(github.event.comment.body, '/submit-checklist')) || - (github.event_name == 'pull_request' && (github.event.action == 'synchronize' || github.event.action == 'reopened' || github.event.action == 'ready_for_review' || github.event.action == 'closed')) - steps: - - name: Get PR number - id: get-pr - uses: actions/github-script@v8 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const prNumber = context.payload.issue.number; - core.setOutput('pr_number', prNumber); - return prNumber; - - - name: Submit and lock checklist - if: github.event_name == 'issue_comment' && contains(github.event.comment.body, '/submit-checklist') - uses: actions/github-script@v8 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - // Check if the command is present (works with quote replies too) - const commentBody = context.payload.comment.body || ''; - if (!commentBody.includes('/submit-checklist')) { - console.log('Submit command not found in comment'); - return; - } - - const prNumber = context.payload.issue.number; - const submitter = context.payload.comment.user.login; - const submitTime = new Date().toISOString(); - const submitDate = new Date().toLocaleString('en-US', { - timeZone: 'UTC', - year: 'numeric', - month: 'long', - day: 'numeric', - hour: '2-digit', - minute: '2-digit', - second: '2-digit', - timeZoneName: 'short' - }); - - // Get all comments to find the checklist - const comments = await github.rest.issues.listComments({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - }); - - const checklistComment = comments.data.find( - comment => comment.user.type === 'Bot' && - comment.body.includes('DevOps Checklist') - ); - - if (!checklistComment) { - console.log('Checklist comment not found'); - return; - } - - // Check if already submitted - if (checklistComment.body.includes('✅ **CHECKLIST SUBMITTED**')) { - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - body: `⚠️ This checklist has already been submitted and cannot be modified.` - }); - return; - } - - // Extract the current checklist content (preserve checkboxes) - let checklistBody = checklistComment.body; - - // Extract submission info to preserve it - const submissionInfo = `**Submitted by:** @${submitter} - **Submitted at:** ${submitDate} (UTC)`; - - // Replace the submission section with submitted status - const submittedSection = `--- - - ### ✅ **CHECKLIST SUBMITTED** - - ${submissionInfo} - - 🔒 **This checklist is now locked and cannot be modified.** - - - - --- - **Note:** This checklist was submitted and is final. No further changes can be made.`; - - // Find and replace the submission section - // Look for the "Submit Checklist" section and replace everything from there to the end - const submitSectionStart = checklistBody.indexOf('### 📤 Submit Checklist'); - if (submitSectionStart !== -1) { - // Keep everything before the submission section, then add the submitted section - checklistBody = checklistBody.substring(0, submitSectionStart) + submittedSection; - } else { - // If section not found, append the submitted section - checklistBody = checklistBody + '\n\n' + submittedSection; - } - - // Extract and store the exact checkbox states before locking - const checkboxStates = []; - const checkboxRegex = /- \[([ x])\] (.+)/g; - let match; - while ((match = checkboxRegex.exec(checklistBody)) !== null) { - checkboxStates.push({ - checked: match[1] === 'x', - text: match[2] - }); - } - - // Store checkbox states in a hidden comment for restoration - const checkboxStatesJson = JSON.stringify(checkboxStates); - - // Update the checklist comment to show it's submitted - await github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: checklistComment.id, - body: checklistBody - }); - - // Add a hidden comment with checkbox states for restoration - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - body: `` - }); - - // Add label to track submission - try { - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - labels: ['devops-checklist-submitted'] - }); - } catch (e) { - // Label might not exist, create it - try { - await github.rest.issues.createLabel({ - owner: context.repo.owner, - repo: context.repo.repo, - name: 'devops-checklist-submitted', - color: '28a745', - description: 'DevOps Checklist has been submitted and locked' - }); - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - labels: ['devops-checklist-submitted'] - }); - } catch (labelError) { - console.log('Could not create/add label:', labelError.message); - } - } - - // Add a confirmation comment - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - body: `✅ **Checklist submitted successfully!** - - The DevOps Checklist has been locked and cannot be modified. - - **Submitted by:** @${submitter} - **Time:** ${submitDate} (UTC)` - }); - - console.log(`Checklist submitted by ${submitter} at ${submitTime}`); - - - name: Re-lock checklist if edited after submission - if: | - (github.event_name == 'issue_comment' && github.event.action == 'edited') || - (github.event_name == 'pull_request') - uses: actions/github-script@v8 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const prNumber = github.event_name == 'issue_comment' - ? context.payload.issue.number - : context.payload.pull_request.number; - - // Get all comments to find the checklist - const comments = await github.rest.issues.listComments({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - }); - - const checklistComment = comments.data.find( - comment => comment.user.type === 'Bot' && - comment.body.includes('DevOps Checklist') - ); - - if (!checklistComment) { - return; - } - - // Check if checklist was previously submitted (look for submission marker) - const hasSubmissionMarker = checklistComment.body.includes('CHECKLIST_SUBMITTED_LOCK'); - const hasSubmittedText = checklistComment.body.includes('✅ **CHECKLIST SUBMITTED**'); - - // If it was submitted, ensure it's locked and restore checkbox states - if (hasSubmissionMarker || hasSubmittedText) { - let checklistBody = checklistComment.body; - - // Get stored checkbox states from hidden comment - let storedStates = null; - const allComments = comments.data; - for (const comment of allComments) { - if (comment.body.includes('CHECKLIST_STATES:')) { - const statesMatch = comment.body.match(/CHECKLIST_STATES:(.+)/); - if (statesMatch) { - try { - storedStates = JSON.parse(statesMatch[1]); - break; - } catch (e) { - console.log('Could not parse stored states'); - } - } - } - } - - // Extract submission info - const submitterMatch = checklistBody.match(/\*\*Submitted by:\*\* @(\S+)/); - const dateMatch = checklistBody.match(/\*\*Submitted at:\*\* (.+?)(?:\n|UTC)/); - const submitter = submitterMatch ? submitterMatch[1] : 'System'; - const submitDate = dateMatch ? dateMatch[1].trim() : new Date().toLocaleString('en-US', { - timeZone: 'UTC', - year: 'numeric', - month: 'long', - day: 'numeric', - hour: '2-digit', - minute: '2-digit', - second: '2-digit', - timeZoneName: 'short' - }); - - // Restore checkbox states if we have stored states - if (storedStates && storedStates.length > 0) { - let restoredBody = checklistBody; - const checkboxRegex = /- \[([ x])\] (.+)/g; - let stateIndex = 0; - - restoredBody = restoredBody.replace(checkboxRegex, (match, checked, text) => { - if (stateIndex < storedStates.length) { - const state = storedStates[stateIndex]; - stateIndex++; - // Restore the original checkbox state - return `- [${state.checked ? 'x' : ' '}] ${state.text}`; - } - return match; - }); - - checklistBody = restoredBody; - } - - // Check if lock section is present and complete - const hasLockMessage = checklistBody.includes('🔒 **This checklist is now locked and cannot be modified.**'); - const hasCompleteLock = hasSubmittedText && hasLockMessage; - - // If lock is missing or incomplete, or checkboxes were changed, restore it - if (!hasCompleteLock || (storedStates && checklistBody !== checklistComment.body)) { - // Find where to insert/update the lock section - const submitIndex = checklistBody.indexOf('### ✅ **CHECKLIST SUBMITTED**'); - const lockSection = `--- - - ### ✅ **CHECKLIST SUBMITTED** - - **Submitted by:** @${submitter} - **Submitted at:** ${submitDate} (UTC) - - 🔒 **This checklist is now locked and cannot be modified.** - - - - --- - **Note:** This checklist was submitted and is final. No further changes can be made.`; - - if (submitIndex !== -1) { - // Replace from submission header to end of comment - const beforeSubmit = checklistBody.substring(0, submitIndex); - checklistBody = beforeSubmit + lockSection; - } else { - // Append lock section if submission header is missing - checklistBody = checklistBody + '\n\n' + lockSection; - } - - // Re-lock the checklist with restored states - await github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: checklistComment.id, - body: checklistBody - }); - - // Add a warning comment only if this is an edit event (not PR sync) - if (github.event_name == 'issue_comment' && github.event.action == 'edited') { - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - body: `⚠️ **Checklist Re-locked** - - The DevOps Checklist was modified after submission. It has been automatically re-locked and restored to its submitted state. - - 🔒 **This checklist cannot be modified once submitted.**` - }); - } - - console.log('Checklist re-locked after unauthorized edit'); - } - } - diff --git a/.github/workflows/devops-checklist.yml b/.github/workflows/devops-checklist.yml index f65a085..8aa6c35 100644 --- a/.github/workflows/devops-checklist.yml +++ b/.github/workflows/devops-checklist.yml @@ -265,7 +265,14 @@ jobs: } // Only create new comment if it doesn't exist - const checklist = `## 🔧 DevOps Checklist + const checklist = `## 🔧 DevOps Checklist Template + + **DevOps Team: Copy the template below, fill it out, and post it as a comment on this PR.** + + --- + + \`\`\` + ## 🔧 DevOps Checklist ### Workflows & Quality - [ ] All CI/CD workflows passing @@ -293,15 +300,14 @@ jobs: - [ ] **NO-GO** - Blocked (see notes) **Notes:** - \`\`\` - + + + **Reviewed by:** @username + **Date:** YYYY-MM-DD \`\`\` --- - - **Submit:** Comment \`/submit-checklist\` to lock this checklist - - ⚠️ Once submitted, this checklist cannot be modified.`; + *Copy the template above, fill it out with your review, and post it as a comment.*`; // Create new comment await github.rest.issues.createComment({ From 36b45c8ba0975b6ef3450e049c7fcfb1dd11857c Mon Sep 17 00:00:00 2001 From: ankitjangir1690 Date: Sun, 30 Nov 2025 20:26:10 +0530 Subject: [PATCH 09/16] fix: improving checklist --- .github/workflows/devops-checklist.yml | 32 +++++--------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/.github/workflows/devops-checklist.yml b/.github/workflows/devops-checklist.yml index 8aa6c35..0779ec0 100644 --- a/.github/workflows/devops-checklist.yml +++ b/.github/workflows/devops-checklist.yml @@ -267,47 +267,27 @@ jobs: // Only create new comment if it doesn't exist const checklist = `## 🔧 DevOps Checklist Template - **DevOps Team: Copy the template below, fill it out, and post it as a comment on this PR.** + 👋 **DevOps Team:** Copy the template below, fill it out, and post it as a comment on this PR. --- - \`\`\` + \`\`\`markdown ## 🔧 DevOps Checklist - ### Workflows & Quality + ### ✅ Workflows & Quality - [ ] All CI/CD workflows passing - [ ] Code quality checks passed - [ ] Security scans passed - [ ] No secrets or credentials exposed - ### Review & Testing - - [ ] Code review approved - - [ ] Tested on staging/UAT - - [ ] No critical bugs pending - - ### Documentation + ### 📝 Documentation - [ ] Deployment notes reviewed - - [ ] Rollback plan documented - [ ] 🔗 [Rollback Guidelines](https://devops.dhwaniris.com/rollback-guidelines) - - ### Deployment Readiness - - [ ] DB migrations ready (if applicable) - - [ ] Config changes documented - - [ ] Monitoring alerts validated - - ### Final Decision - - [ ] **GO** - Ready for production - - [ ] **NO-GO** - Blocked (see notes) - - **Notes:** - - - **Reviewed by:** @username - **Date:** YYYY-MM-DD \`\`\` --- - *Copy the template above, fill it out with your review, and post it as a comment.*`; + + 💡 **Instructions:** Copy the template above, check the boxes (replace \`[ ]\` with \`[x]\`), and post it as a comment.`; // Create new comment await github.rest.issues.createComment({ From 153ed8707ceb2ebeb05ac2f907fd4d44e3c40837 Mon Sep 17 00:00:00 2001 From: ankitjangir1690 Date: Sun, 30 Nov 2025 20:30:52 +0530 Subject: [PATCH 10/16] fix: improving checklist --- .github/workflows/add-pr-to-devops.yml | 57 ++++++++++++++++++++++++++ .github/workflows/devops-checklist.yml | 10 ++--- 2 files changed, 60 insertions(+), 7 deletions(-) diff --git a/.github/workflows/add-pr-to-devops.yml b/.github/workflows/add-pr-to-devops.yml index 08b6733..2a371ac 100644 --- a/.github/workflows/add-pr-to-devops.yml +++ b/.github/workflows/add-pr-to-devops.yml @@ -22,4 +22,61 @@ jobs: with: project-url: https://github.com/orgs/dhwani-ris/projects/## github-token: ${{ secrets.GITHUB_TOKEN }} + content-id: ${{ github.event.pull_request.node_id }} + content-type: PullRequest + continue-on-error: true + + - name: Alternative - Add PR using GitHub API + if: failure() + uses: actions/github-script@v8 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + // Alternative method using GitHub API + const prNodeId = context.payload.pull_request.node_id; + const projectNumber = '##'; // Replace with actual project number + + try { + // Get organization projects + const { data: projects } = await github.rest.projects.listForOrg({ + org: 'dhwani-ris', + state: 'open' + }); + + // Find the DevOps Release & QC Board project + const devopsProject = projects.find(p => + p.name.includes('DevOps') || + p.name.includes('Release') || + p.name.includes('QC') + ); + + if (!devopsProject) { + console.log('DevOps project not found'); + return; + } + + // Get project columns + const { data: columns } = await github.rest.projects.listColumns({ + project_id: devopsProject.id + }); + + if (columns.length === 0) { + console.log('No columns found in project'); + return; + } + + // Add PR to the first column (usually "To do" or "In progress") + const firstColumn = columns[0]; + + await github.rest.projects.createCard({ + column_id: firstColumn.id, + content_id: prNodeId, + content_type: 'PullRequest' + }); + + console.log(`✅ Added PR #${context.payload.pull_request.number} to DevOps board`); + } catch (error) { + console.log('Error adding to project:', error.message); + console.log('Note: Make sure GITHUB_TOKEN has organization project permissions or use a PAT'); + } diff --git a/.github/workflows/devops-checklist.yml b/.github/workflows/devops-checklist.yml index 0779ec0..49b02dc 100644 --- a/.github/workflows/devops-checklist.yml +++ b/.github/workflows/devops-checklist.yml @@ -265,15 +265,12 @@ jobs: } // Only create new comment if it doesn't exist - const checklist = `## 🔧 DevOps Checklist Template + const checklist = `## 🔧 DevOps Checklist - 👋 **DevOps Team:** Copy the template below, fill it out, and post it as a comment on this PR. + 👋 **DevOps Team:** Please review and check the items below. --- - \`\`\`markdown - ## 🔧 DevOps Checklist - ### ✅ Workflows & Quality - [ ] All CI/CD workflows passing - [ ] Code quality checks passed @@ -283,11 +280,10 @@ jobs: ### 📝 Documentation - [ ] Deployment notes reviewed - [ ] 🔗 [Rollback Guidelines](https://devops.dhwaniris.com/rollback-guidelines) - \`\`\` --- - 💡 **Instructions:** Copy the template above, check the boxes (replace \`[ ]\` with \`[x]\`), and post it as a comment.`; + 💡 *Click the checkboxes above to mark items as complete.*`; // Create new comment await github.rest.issues.createComment({ From 1966ecfdba7243d337b47f007c2542aeec5f6ba9 Mon Sep 17 00:00:00 2001 From: ankitjangir1690 Date: Sun, 30 Nov 2025 20:49:27 +0530 Subject: [PATCH 11/16] feat: automatic pr adds to org project devops qc --- .github/workflows/add-pr-to-devops.yml | 41 ++++++++++++++------------ 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/.github/workflows/add-pr-to-devops.yml b/.github/workflows/add-pr-to-devops.yml index 2a371ac..8862f1d 100644 --- a/.github/workflows/add-pr-to-devops.yml +++ b/.github/workflows/add-pr-to-devops.yml @@ -18,23 +18,12 @@ jobs: organization-projects: write steps: - name: Add PR to DevOps Release Board - uses: actions/add-to-project@v0.5.0 - with: - project-url: https://github.com/orgs/dhwani-ris/projects/## - github-token: ${{ secrets.GITHUB_TOKEN }} - content-id: ${{ github.event.pull_request.node_id }} - content-type: PullRequest - continue-on-error: true - - - name: Alternative - Add PR using GitHub API - if: failure() uses: actions/github-script@v8 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | - // Alternative method using GitHub API const prNodeId = context.payload.pull_request.node_id; - const projectNumber = '##'; // Replace with actual project number + const prNumber = context.payload.pull_request.number; try { // Get organization projects @@ -43,18 +32,22 @@ jobs: state: 'open' }); + console.log(`Found ${projects.length} organization projects`); + // Find the DevOps Release & QC Board project const devopsProject = projects.find(p => - p.name.includes('DevOps') || - p.name.includes('Release') || - p.name.includes('QC') + p.name.toLowerCase().includes('devops') && + (p.name.toLowerCase().includes('release') || p.name.toLowerCase().includes('qc')) ); if (!devopsProject) { - console.log('DevOps project not found'); + console.log('DevOps Release & QC Board project not found'); + console.log('Available projects:', projects.map(p => p.name).join(', ')); return; } + console.log(`Found project: ${devopsProject.name} (ID: ${devopsProject.id})`); + // Get project columns const { data: columns } = await github.rest.projects.listColumns({ project_id: devopsProject.id @@ -65,6 +58,8 @@ jobs: return; } + console.log(`Found ${columns.length} columns:`, columns.map(c => c.name).join(', ')); + // Add PR to the first column (usually "To do" or "In progress") const firstColumn = columns[0]; @@ -74,9 +69,17 @@ jobs: content_type: 'PullRequest' }); - console.log(`✅ Added PR #${context.payload.pull_request.number} to DevOps board`); + console.log(`✅ Successfully added PR #${prNumber} to DevOps Release & QC Board`); + console.log(` Project: ${devopsProject.name}`); + console.log(` Column: ${firstColumn.name}`); } catch (error) { - console.log('Error adding to project:', error.message); - console.log('Note: Make sure GITHUB_TOKEN has organization project permissions or use a PAT'); + console.log('❌ Error adding PR to project:', error.message); + if (error.status === 403) { + console.log('⚠️ Permission denied. GITHUB_TOKEN may not have organization project access.'); + console.log(' Consider using a Personal Access Token (PAT) with project scope.'); + } else if (error.status === 404) { + console.log('⚠️ Project or column not found. Check project name and permissions.'); + } + throw error; } From 3108df55fca325b5874f625737db9f3a22504423 Mon Sep 17 00:00:00 2001 From: ankitjangir1690 Date: Sun, 30 Nov 2025 23:43:40 +0530 Subject: [PATCH 12/16] fix: improving checklist --- .github/workflows/devops-checklist.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/devops-checklist.yml b/.github/workflows/devops-checklist.yml index 49b02dc..ba7ea48 100644 --- a/.github/workflows/devops-checklist.yml +++ b/.github/workflows/devops-checklist.yml @@ -271,15 +271,15 @@ jobs: --- - ### ✅ Workflows & Quality - - [ ] All CI/CD workflows passing - - [ ] Code quality checks passed - - [ ] Security scans passed - - [ ] No secrets or credentials exposed + ### ✅ Pre-Merge Verification + - [ ] All CI/CD workflows passing (check Actions tab) + - [ ] Code quality checks passed (Semgrep, Pre-commit) + - [ ] Security scans passed (no vulnerabilities) + - [ ] No secrets or credentials exposed (manual review) ### 📝 Documentation - - [ ] Deployment notes reviewed - - [ ] 🔗 [Rollback Guidelines](https://devops.dhwaniris.com/rollback-guidelines) + - [ ] Deployment notes reviewed (see comment above) + - [ ] 🔗 [Rollback Guidelines](https://dhwaniris1-my.sharepoint.com/:b:/g/personal/technology_dhwaniris_com/IQBZ-x3H8jIjQoliD_JEKHfSAQq2pMXdy8wFAdISg7fInTE?e=gd7dsq) reviewed --- From 3ce36d83fa176e1ae6c996a47f3675e1c599b0b2 Mon Sep 17 00:00:00 2001 From: ankitjangir1690 Date: Mon, 1 Dec 2025 00:00:15 +0530 Subject: [PATCH 13/16] fix: project viisbility --- .github/workflows/add-pr-to-devops.yml | 81 ++++++++++++++++++++------ 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/.github/workflows/add-pr-to-devops.yml b/.github/workflows/add-pr-to-devops.yml index 8862f1d..3a5d4da 100644 --- a/.github/workflows/add-pr-to-devops.yml +++ b/.github/workflows/add-pr-to-devops.yml @@ -24,6 +24,9 @@ jobs: script: | const prNodeId = context.payload.pull_request.node_id; const prNumber = context.payload.pull_request.number; + const prUrl = context.payload.pull_request.html_url; + + console.log(`Processing PR #${prNumber} (Node ID: ${prNodeId})`); try { // Get organization projects @@ -34,19 +37,37 @@ jobs: console.log(`Found ${projects.length} organization projects`); - // Find the DevOps Release & QC Board project - const devopsProject = projects.find(p => - p.name.toLowerCase().includes('devops') && - (p.name.toLowerCase().includes('release') || p.name.toLowerCase().includes('qc')) - ); + if (projects.length === 0) { + console.log('⚠️ No organization projects found. Check permissions.'); + return; + } + + // Log all project names for debugging + console.log('Available projects:', projects.map(p => `"${p.name}" (ID: ${p.id})`).join(', ')); + + // Find the DevOps Release & QC Board project - try multiple name patterns + let devopsProject = projects.find(p => { + const name = p.name.toLowerCase(); + return (name.includes('devops') && name.includes('release')) || + (name.includes('devops') && name.includes('qc')) || + (name.includes('devops') && name.includes('board')); + }); + + // If not found, try just "devops" + if (!devopsProject) { + devopsProject = projects.find(p => + p.name.toLowerCase().includes('devops') + ); + } if (!devopsProject) { - console.log('DevOps Release & QC Board project not found'); - console.log('Available projects:', projects.map(p => p.name).join(', ')); + console.log('❌ DevOps Release & QC Board project not found'); + console.log('Available project names:', projects.map(p => p.name).join(', ')); + console.log('Please check the project name matches: "DevOps", "Release", or "QC"'); return; } - console.log(`Found project: ${devopsProject.name} (ID: ${devopsProject.id})`); + console.log(`✅ Found project: "${devopsProject.name}" (ID: ${devopsProject.id})`); // Get project columns const { data: columns } = await github.rest.projects.listColumns({ @@ -54,15 +75,31 @@ jobs: }); if (columns.length === 0) { - console.log('No columns found in project'); + console.log('❌ No columns found in project'); return; } - console.log(`Found ${columns.length} columns:`, columns.map(c => c.name).join(', ')); + console.log(`Found ${columns.length} columns:`, columns.map(c => `"${c.name}"`).join(', ')); - // Add PR to the first column (usually "To do" or "In progress") + // Find the first column (usually "To do", "In progress", or "Backlog") const firstColumn = columns[0]; + console.log(`Adding PR to column: "${firstColumn.name}"`); + // Check if PR is already in the project + const { data: cards } = await github.rest.projects.listCards({ + column_id: firstColumn.id + }); + + const alreadyAdded = cards.some(card => + card.content_url && card.content_url.includes(`/pulls/${prNumber}`) + ); + + if (alreadyAdded) { + console.log(`✅ PR #${prNumber} is already in the project`); + return; + } + + // Add PR to the first column await github.rest.projects.createCard({ column_id: firstColumn.id, content_id: prNodeId, @@ -70,16 +107,26 @@ jobs: }); console.log(`✅ Successfully added PR #${prNumber} to DevOps Release & QC Board`); - console.log(` Project: ${devopsProject.name}`); - console.log(` Column: ${firstColumn.name}`); + console.log(` Project: "${devopsProject.name}"`); + console.log(` Column: "${firstColumn.name}"`); + console.log(` PR URL: ${prUrl}`); } catch (error) { console.log('❌ Error adding PR to project:', error.message); + console.log('Error details:', JSON.stringify(error, null, 2)); + if (error.status === 403) { - console.log('⚠️ Permission denied. GITHUB_TOKEN may not have organization project access.'); - console.log(' Consider using a Personal Access Token (PAT) with project scope.'); + console.log('⚠️ Permission denied (403). GITHUB_TOKEN may not have organization project access.'); + console.log(' Solution: Use a Personal Access Token (PAT) with "project" scope.'); + console.log(' 1. Create PAT at: https://github.com/settings/tokens'); + console.log(' 2. Add it as secret: PROJECT_TOKEN'); + console.log(' 3. Update workflow to use: ${{ secrets.PROJECT_TOKEN }}'); } else if (error.status === 404) { - console.log('⚠️ Project or column not found. Check project name and permissions.'); + console.log('⚠️ Not found (404). Check project name and permissions.'); + } else if (error.status === 401) { + console.log('⚠️ Unauthorized (401). Token may be invalid or expired.'); } - throw error; + + // Don't fail the workflow, just log the error + console.log('⚠️ Continuing workflow despite error...'); } From 0db509b27ae75173c6981fb3067ff40467a1a24e Mon Sep 17 00:00:00 2001 From: ankitjangir1690 Date: Mon, 1 Dec 2025 00:03:45 +0530 Subject: [PATCH 14/16] fix: project viisbility --- .github/workflows/add-pr-to-devops.yml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/.github/workflows/add-pr-to-devops.yml b/.github/workflows/add-pr-to-devops.yml index 3a5d4da..a1fcc74 100644 --- a/.github/workflows/add-pr-to-devops.yml +++ b/.github/workflows/add-pr-to-devops.yml @@ -20,7 +20,7 @@ jobs: - name: Add PR to DevOps Release Board uses: actions/github-script@v8 with: - github-token: ${{ secrets.GITHUB_TOKEN }} + github-token: ${{ secrets.PROJECT_TOKEN || secrets.GITHUB_TOKEN }} script: | const prNodeId = context.payload.pull_request.node_id; const prNumber = context.payload.pull_request.number; @@ -45,12 +45,17 @@ jobs: // Log all project names for debugging console.log('Available projects:', projects.map(p => `"${p.name}" (ID: ${p.id})`).join(', ')); - // Find the DevOps Release & QC Board project - try multiple name patterns + // Find the DevOps Release & QC Board project - try exact match first + // Project name from UI: "Dhwani - DevOps Release & QC Board" let devopsProject = projects.find(p => { const name = p.name.toLowerCase(); - return (name.includes('devops') && name.includes('release')) || - (name.includes('devops') && name.includes('qc')) || - (name.includes('devops') && name.includes('board')); + // Try exact match or close match + return name === 'dhwani - devops release & qc board' || + name === 'dhwani – devops release & qc board' || // Different dash character + (name.includes('dhwani') && name.includes('devops') && name.includes('release') && name.includes('qc')) || + (name.includes('devops') && name.includes('release') && name.includes('qc')) || + (name.includes('devops') && name.includes('release')) || + (name.includes('devops') && name.includes('qc')); }); // If not found, try just "devops" From 3098d87cd656f9678c12269f90da968835812e00 Mon Sep 17 00:00:00 2001 From: ankitjangir1690 Date: Mon, 1 Dec 2025 11:26:17 +0530 Subject: [PATCH 15/16] feat: adding OWASP Dependency-Check and CODEOWNER to devops team --- .github/CODEOWNERS | 14 ++++++++ .github/workflows/security-scan.yml | 52 +++++++++++++++++++++++++++-- 2 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..a33bba7 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,14 @@ +# CODEOWNERS file +# This file defines code owners for the repository +# See: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners + +# DevOps team owns all files +* @dhwani-ris/dhwani-devops + +# GitHub workflows - DevOps team +/.github/workflows/ @dhwani-ris/dhwani-devops + +# Configuration files - DevOps team +/.github/ @dhwani-ris/dhwani-devops +/.releaserc @dhwani-ris/dhwani-devops + diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml index 491df7b..d7822ff 100644 --- a/.github/workflows/security-scan.yml +++ b/.github/workflows/security-scan.yml @@ -82,6 +82,26 @@ jobs: with: python-version: '3.13' + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Run OWASP Dependency-Check + uses: dependency-check/Dependency-Check_Action@main + id: depcheck + with: + project: 'gatepass-check' + path: '.' + format: 'JSON' + args: > + --enableRetired + --enableExperimental + --failOnCVSS 7 + --out reports + token: ${{ secrets.GITHUB_TOKEN }} + continue-on-error: true + - name: Run pip-audit run: | pip install pip-audit @@ -102,6 +122,7 @@ jobs: with: name: security-reports-${{ github.run_id }} path: | + reports/dependency-check-report.json pip-audit-report.json safety-report.json bandit-report.json @@ -119,6 +140,31 @@ jobs: let comment = '## 🔒 Security Scan Results\n\n'; let hasIssues = false; + // Check OWASP Dependency-Check + try { + if (fs.existsSync('reports/dependency-check-report.json')) { + const report = JSON.parse(fs.readFileSync('reports/dependency-check-report.json', 'utf8')); + if (report.dependencies && report.dependencies.length > 0) { + const vulnerableDeps = report.dependencies.filter(dep => + dep.vulnerabilities && dep.vulnerabilities.length > 0 + ); + if (vulnerableDeps.length > 0) { + hasIssues = true; + comment += `### ⚠️ OWASP Dependency-Check Findings\n\n`; + comment += `Found ${vulnerableDeps.length} vulnerable dependency(ies) with ${vulnerableDeps.reduce((sum, d) => sum + d.vulnerabilities.length, 0)} total vulnerability(ies).\n\n`; + vulnerableDeps.slice(0, 10).forEach(dep => { + const cves = dep.vulnerabilities.map(v => v.name).join(', '); + const severity = dep.vulnerabilities.map(v => v.severity || 'UNKNOWN').join(', '); + comment += `- **${dep.fileName || dep.packagePath}**: ${cves} (Severity: ${severity})\n`; + }); + comment += `\n`; + } + } + } + } catch (e) { + console.log('Error reading OWASP Dependency-Check report:', e); + } + // Check pip-audit try { if (fs.existsSync('pip-audit-report.json')) { @@ -208,7 +254,7 @@ jobs: security-summary: name: Security Summary runs-on: ubuntu-latest - needs: [codeql-analysis, secret-scanning, dependency-scanning] + needs: [codeql-analysis, secret-scanning, dependency-scanning, container-scanning] if: always() steps: @@ -224,7 +270,9 @@ jobs: |-----------|--------| | CodeQL Analysis | ${needs.codeql-analysis.result === 'success' ? '✅ Passed' : needs.codeql-analysis.result === 'failure' ? '❌ Failed' : '⚠️ Skipped'} | | Secret Scanning | ${needs.secret-scanning.result === 'success' ? '✅ Passed' : needs.secret-scanning.result === 'failure' ? '❌ Failed' : '⚠️ Skipped'} | - | Dependency Scan | ${needs.dependency-scanning.result === 'success' ? '✅ Passed' : needs.dependency-scanning.result === 'failure' ? '❌ Failed' : '⚠️ Skipped'} | + | OWASP Dependency-Check | ${needs.dependency-scanning.result === 'success' ? '✅ Passed' : needs.dependency-scanning.result === 'failure' ? '❌ Failed' : '⚠️ Skipped'} | + | Dependency Scan (pip-audit/safety) | ${needs.dependency-scanning.result === 'success' ? '✅ Passed' : needs.dependency-scanning.result === 'failure' ? '❌ Failed' : '⚠️ Skipped'} | + | Container Scan (Trivy) | ${needs.container-scanning && needs.container-scanning.result === 'success' ? '✅ Passed' : needs.container-scanning && needs.container-scanning.result === 'failure' ? '❌ Failed' : '⚠️ Skipped'} | **View detailed results in the Security tab or workflow artifacts.**`; From c863dee05af94372731a209d6103798722b72117 Mon Sep 17 00:00:00 2001 From: ankitjangir1690 Date: Mon, 1 Dec 2025 11:33:44 +0530 Subject: [PATCH 16/16] fix: fixing adding project and review thing --- .github/workflows/add-pr-to-devops.yml | 77 +++++++++++++++----------- .github/workflows/auto-reviewer.yml | 51 +++++++++++------ 2 files changed, 81 insertions(+), 47 deletions(-) diff --git a/.github/workflows/add-pr-to-devops.yml b/.github/workflows/add-pr-to-devops.yml index a1fcc74..dc3608f 100644 --- a/.github/workflows/add-pr-to-devops.yml +++ b/.github/workflows/add-pr-to-devops.yml @@ -2,15 +2,17 @@ name: Add PR to DevOps Board on: pull_request: - types: [opened, reopened] - branches: [main, master] + types: [opened, reopened, synchronize] + branches: [main, master, develop, development] jobs: add_to_project: runs-on: ubuntu-latest if: | github.event.pull_request.base.ref == 'main' || - github.event.pull_request.base.ref == 'master' + github.event.pull_request.base.ref == 'master' || + github.event.pull_request.base.ref == 'develop' || + github.event.pull_request.base.ref == 'development' permissions: contents: read pull-requests: write @@ -46,14 +48,19 @@ jobs: console.log('Available projects:', projects.map(p => `"${p.name}" (ID: ${p.id})`).join(', ')); // Find the DevOps Release & QC Board project - try exact match first - // Project name from UI: "Dhwani - DevOps Release & QC Board" + // Project name from UI: "Dhwani – DevOps Release & QC Board" (with en-dash) let devopsProject = projects.find(p => { const name = p.name.toLowerCase(); - // Try exact match or close match + // Try exact match with various dash characters (hyphen, en-dash, em-dash) return name === 'dhwani - devops release & qc board' || - name === 'dhwani – devops release & qc board' || // Different dash character + name === 'dhwani – devops release & qc board' || // en-dash (U+2013) + name === 'dhwani — devops release & qc board' || // em-dash (U+2014) + name === 'dhwani - devops release and qc board' || + name === 'dhwani – devops release and qc board' || (name.includes('dhwani') && name.includes('devops') && name.includes('release') && name.includes('qc')) || + (name.includes('dhwani') && name.includes('devops') && name.includes('release') && name.includes('board')) || (name.includes('devops') && name.includes('release') && name.includes('qc')) || + (name.includes('devops') && name.includes('release') && name.includes('board')) || (name.includes('devops') && name.includes('release')) || (name.includes('devops') && name.includes('qc')); }); @@ -67,8 +74,13 @@ jobs: if (!devopsProject) { console.log('❌ DevOps Release & QC Board project not found'); - console.log('Available project names:', projects.map(p => p.name).join(', ')); - console.log('Please check the project name matches: "DevOps", "Release", or "QC"'); + console.log('Available project names:', projects.map(p => `"${p.name}"`).join(', ')); + console.log('Searched for: "Dhwani – DevOps Release & QC Board" (with en-dash)'); + console.log('Please check:'); + console.log(' 1. Project name matches: "DevOps", "Release", or "QC"'); + console.log(' 2. Project is in the dhwani-ris organization'); + console.log(' 3. GITHUB_TOKEN has organization project access'); + console.log(' 4. Consider using PROJECT_TOKEN secret with "project" scope'); return; } @@ -90,31 +102,34 @@ jobs: const firstColumn = columns[0]; console.log(`Adding PR to column: "${firstColumn.name}"`); - // Check if PR is already in the project - const { data: cards } = await github.rest.projects.listCards({ - column_id: firstColumn.id - }); - - const alreadyAdded = cards.some(card => - card.content_url && card.content_url.includes(`/pulls/${prNumber}`) - ); - - if (alreadyAdded) { - console.log(`✅ PR #${prNumber} is already in the project`); - return; + // Check if PR is already in the project (check all columns) + let alreadyAdded = false; + for (const column of columns) { + const { data: cards } = await github.rest.projects.listCards({ + column_id: column.id + }); + alreadyAdded = cards.some(card => + card.content_url && card.content_url.includes(`/pulls/${prNumber}`) + ); + if (alreadyAdded) { + console.log(`✅ PR #${prNumber} is already in the project (column: ${column.name})`); + break; + } } - // Add PR to the first column - await github.rest.projects.createCard({ - column_id: firstColumn.id, - content_id: prNodeId, - content_type: 'PullRequest' - }); - - console.log(`✅ Successfully added PR #${prNumber} to DevOps Release & QC Board`); - console.log(` Project: "${devopsProject.name}"`); - console.log(` Column: "${firstColumn.name}"`); - console.log(` PR URL: ${prUrl}`); + if (!alreadyAdded) { + // Add PR to the first column + await github.rest.projects.createCard({ + column_id: firstColumn.id, + content_id: prNodeId, + content_type: 'PullRequest' + }); + + console.log(`✅ Successfully added PR #${prNumber} to DevOps Release & QC Board`); + console.log(` Project: "${devopsProject.name}"`); + console.log(` Column: "${firstColumn.name}"`); + console.log(` PR URL: ${prUrl}`); + } } catch (error) { console.log('❌ Error adding PR to project:', error.message); console.log('Error details:', JSON.stringify(error, null, 2)); diff --git a/.github/workflows/auto-reviewer.yml b/.github/workflows/auto-reviewer.yml index f97e436..bc383a5 100644 --- a/.github/workflows/auto-reviewer.yml +++ b/.github/workflows/auto-reviewer.yml @@ -3,7 +3,7 @@ name: Auto Request Review on: pull_request: types: [opened, synchronize, reopened, ready_for_review, closed] - branches: [master] + branches: [main, master, develop, development] permissions: pull-requests: write @@ -47,27 +47,46 @@ jobs: console.log('Current reviewers:', JSON.stringify(currentReviews, null, 2)); - // Check if reviewer is already requested - const isAlreadyRequested = currentReviews.users?.some( + // Check if DevOps team is already requested + const devopsTeam = 'dhwani-ris/dhwani-devops'; + const isTeamRequested = currentReviews.teams?.some( + team => `${team.organization.login}/${team.slug}` === devopsTeam + ); + + // Check if individual reviewer is already requested + const isUserRequested = currentReviews.users?.some( user => user.login.toLowerCase() === reviewer.toLowerCase() - ) || currentReviews.teams?.some( - team => team.slug.toLowerCase() === reviewer.toLowerCase() ); - if (isAlreadyRequested) { - console.log(`✅ Review already requested from ${reviewer}`); - return; + // Request review from DevOps team (from CODEOWNERS) + if (!isTeamRequested) { + try { + await github.rest.pulls.requestReviewers({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: pr.number, + team_reviewers: ['dhwani-devops'], + }); + console.log(`✅ Successfully requested review from ${devopsTeam}`); + } catch (teamError) { + console.log(`⚠️ Could not request review from team ${devopsTeam}:`, teamError.message); + } + } else { + console.log(`✅ Review already requested from ${devopsTeam}`); } // Request review from default reviewer - await github.rest.pulls.requestReviewers({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: pr.number, - reviewers: [reviewer], - }); - - console.log(`✅ Successfully requested review from ${reviewer}`); + if (!isUserRequested) { + await github.rest.pulls.requestReviewers({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: pr.number, + reviewers: [reviewer], + }); + console.log(`✅ Successfully requested review from ${reviewer}`); + } else { + console.log(`✅ Review already requested from ${reviewer}`); + } } catch (error) { console.error(`❌ Error requesting review from ${reviewer}:`, error); console.error('Error details:', JSON.stringify(error, null, 2));