diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..3c34ba5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,80 @@ +name: "๐Ÿ› Bug Report" +description: Report something that is currently broken or failing in production. +title: "[Bug] " +labels: ["type:bug"] +body: + - type: textarea + id: current-behavior + attributes: + label: "๐Ÿšจ Current Behavior" + description: Clear description of what is failing right now. + validations: + required: true + + - type: textarea + id: expected-behavior + attributes: + label: "๐ŸŽฏ Expected Behavior" + description: What should be happening instead? + validations: + required: true + + - type: textarea + id: impact-if-fixed + attributes: + label: "๐Ÿ’ฅ End-User Impact โ€” if the bug is fixed" + description: What is the impact on the current customer if the bug is fixed? + placeholder: | + e.g., Blocked from completing checkout, visual styling issue only, data loss risk, minor workaround required + validations: + required: true + + - type: textarea + id: impact-if-not-fixed + attributes: + label: "๐Ÿ’ฅ End-User Impact โ€” if the bug is NOT fixed" + description: What is the impact on the current customer if the bug is NOT fixed? + placeholder: | + e.g., Customer remains completely blocked from completing checkout, continuous risk of missing compliance audit windows, minor manual workaround remains required daily + validations: + required: true + + - type: textarea + id: steps-to-reproduce + attributes: + label: "๐Ÿ‘ฃ Steps to Reproduce" + description: Steps to reproduce the behavior. + placeholder: | + 1. Go to '...' + 2. Click on '....' + 3. Scroll down to '....' + 4. See error message: [Paste error log or screenshot here] + validations: + required: true + + - type: input + id: release-version + attributes: + label: "๐Ÿ’ป Release Version" + description: Release version, or commit date if on main + placeholder: "[or commit date if in main]" + validations: + required: true + + - type: textarea + id: verification-plan + attributes: + label: "๐Ÿงช Verification & Validation Plan" + description: How was this validated? + placeholder: | + e.g., Checked staging logs, verified with solid testing evidence, reproduced locally with automated test suite + validations: + required: true + + - type: checkboxes + id: verification-checklist + attributes: + label: "๐Ÿงช Verification Checklist" + options: + - label: Bug patch verified successfully in target environment. + - label: Regression testing completed to ensure nearby features are unaffected. diff --git a/.github/ISSUE_TEMPLATE/epic.yml b/.github/ISSUE_TEMPLATE/epic.yml new file mode 100644 index 0000000..5cf864a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/epic.yml @@ -0,0 +1,61 @@ +name: "๐Ÿ“š Epic" +description: A parent issue that groups a set of user stories toward one outcome. +title: "[Epic] " +labels: ["type:epic"] +body: + - type: markdown + attributes: + value: | + An epic is a **set of stories**, not a story itself. Size and sprint + the child stories. Leave this issue unpointed and off the sprint. + After filing, add those stories as GitHub sub-issues of this epic. + + - type: textarea + id: outcome + attributes: + label: "๐ŸŽฏ Outcome" + description: What will be true when this epic is complete? + placeholder: One or two sentences describing the user or business outcome. + validations: + required: true + + - type: textarea + id: why + attributes: + label: "๐Ÿ’ก Why this epic" + description: Why this work, and why now? + validations: + required: true + + - type: textarea + id: stories + attributes: + label: "๐Ÿ“– Stories" + description: List the user stories in this epic. After this issue is created, add each as a GitHub sub-issue. Do not size this epic. + placeholder: | + - [ ] [Story] ... + - [ ] [Story] ... + - [ ] [Story] ... + validations: + required: true + + - type: textarea + id: out-of-scope + attributes: + label: "๐Ÿšซ Out of Scope" + description: What is explicitly not included in this epic? + placeholder: | + - [ ] Item 1 + - [ ] Item 2 + validations: + required: false + + - type: checkboxes + id: definition-of-done + attributes: + label: "๐Ÿ Definition of Done" + options: + - label: Child stories are filed as GitHub sub-issues of this epic. + - label: This epic is not sized; Size lives on the child stories. + - label: This epic is not assigned to a sprint; stories are. + - label: All child stories are complete and the outcome above is met. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..4ac0f4f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,76 @@ +name: "๐Ÿš€ Feature" +description: Propose a new feature, optimization, or improvement +title: "[Feature] " +labels: ["type:enhancement"] +body: + - type: textarea + id: problem-description + attributes: + label: "๐Ÿ“ Problem Description" + description: A clear and concise description of what the problem or limitation is. + validations: + required: true + + - type: textarea + id: proposed-solution + attributes: + label: "๐Ÿ’ก Proposed Solution" + description: A clear description of what you want to happen and how this feature should look or function. + validations: + required: true + + - type: textarea + id: benefit-if-done + attributes: + label: "๐Ÿ’Ž Current customer & Community Benefit โ€” if we do this" + description: Who benefits from this and why? + placeholder: | + e.g., Saves developers 20 minutes per day, reduces API load for self-hosted community instances, cleans up UI noise for end-users + validations: + required: true + + - type: textarea + id: impact-if-not-done + attributes: + label: "๐Ÿ’Ž Current customer & Community Benefit โ€” if we DO NOT do this" + description: What happens to our current stakeholders if we DO NOT do this? + placeholder: | + e.g., The team will continue to accumulate manual maintenance debt, API costs will scale linearly with traffic, the user experience remains fragmented and hard to adopt for external community members + validations: + required: true + + - type: textarea + id: validation-plan + attributes: + label: "๐Ÿงช Technical Validation & Verification Plan" + description: How should this feature be validated once built? + placeholder: | + e.g., Provide a script to verify structural data output, benchmark database performance, manually check responsive scaling + validations: + required: true + + - type: checkboxes + id: validation-checklist + attributes: + label: "๐Ÿงช Verification Checklist" + options: + - label: Automated testing evidence provided (Unit or Integration tests). + - label: Feature verified successfully in a target staging environment. + + - type: checkboxes + id: definition-of-done-quality + attributes: + label: "๐Ÿ Definition of Done โ€” ๐Ÿ› ๏ธ Quality & Testing" + options: + - label: Code has been peer-reviewed for bugs and vulnerabilities. + - label: Proper testing has been completed and passed (Unit, Integration, E2E via GitHub Actions). + - label: The feature has been demonstrated/validated successfully in the target environment. + + - type: checkboxes + id: definition-of-done-docs + attributes: + label: "๐Ÿ Definition of Done โ€” ๐Ÿ“ Architecture & Docs" + options: + - label: Usage documentation or changelog updated (if user-facing changes introduced). + - label: Local ADR written and verified by Architecture & Alignment Committee if technical architecture deviated. + - label: Any newly introduced technical debt has been logged as a GitHub Intake. diff --git a/.github/ISSUE_TEMPLATE/spike.yml b/.github/ISSUE_TEMPLATE/spike.yml new file mode 100644 index 0000000..0fb9f4c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/spike.yml @@ -0,0 +1,32 @@ +name: "๐Ÿ”ฌ Spike" +description: Time-boxed investigation to explore a technical approach or clear up uncertainty. +title: "[Spike] " +labels: ["type:spike"] +body: + - type: textarea + id: core-question + attributes: + label: "โ“ The Core Question" + description: What specific technical unknown are we trying to answer with this exploration? + placeholder: | + Example: Can our architecture handle 500 simultaneous requests on mobile viewports? + validations: + required: true + + - type: input + id: time-allocated + attributes: + label: "โฑ๏ธ Time Allocated" + description: Time-box for this spike + placeholder: "e.g., 4 Hours / Max 1 Day" + validations: + required: true + + - type: checkboxes + id: required-deliverables + attributes: + label: "๐Ÿ Required Deliverables" + options: + - label: Written summary of findings added as a comment below or linked markdown file. + - label: Proof of Concept (PoC) code shared when applicable (branch, fork, or local investigation notes). + - label: Clear "Go / No-Go" technical recommendation for the Architect. diff --git a/.github/ISSUE_TEMPLATE/task.yml b/.github/ISSUE_TEMPLATE/task.yml new file mode 100644 index 0000000..9513117 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/task.yml @@ -0,0 +1,32 @@ +name: "โš™๏ธ Task" +description: A technical delivery task that does not directly introduce a new user-facing feature. +title: "[Task] " +labels: ["type:task"] +body: + - type: textarea + id: description + attributes: + label: "๐Ÿ“ Description" + description: Provide a clear, technical overview of what needs to be changed in the codebase. + validations: + required: true + + - type: textarea + id: technical-checklist + attributes: + label: "๐Ÿ› ๏ธ Technical Checklist" + description: Steps to complete this task. + placeholder: | + - [ ] Step 1 (e.g., Run database migration scripts) + - [ ] Step 2 (e.g., Update configuration variables in environment files) + - [ ] Step 3 + validations: + required: true + + - type: checkboxes + id: verification-plan + attributes: + label: "๐Ÿงช Verification Plan" + options: + - label: Peer review completed. + - label: All CI/CD checks pass successfully in GitHub Actions. diff --git a/.github/ISSUE_TEMPLATE/user_story.yml b/.github/ISSUE_TEMPLATE/user_story.yml new file mode 100644 index 0000000..5ff99ca --- /dev/null +++ b/.github/ISSUE_TEMPLATE/user_story.yml @@ -0,0 +1,74 @@ +name: "๐Ÿ“– User Story" +description: Describe a feature or user outcome from the user's perspective. +title: "[Story] " +labels: ["type:story"] +body: + - type: markdown + attributes: + value: | + ### ๐Ÿ‘ค User Story + - type: input + id: as-a + attributes: + label: "As a" + description: Type of user + placeholder: "[type of user]" + validations: + required: true + - type: input + id: i-want + attributes: + label: "I want to" + description: Perform an action / have a capability + placeholder: "[perform an action / have a capability]" + validations: + required: true + - type: input + id: so-that + attributes: + label: "So that" + description: The business value or benefit received + placeholder: "[the business value or benefit received]" + validations: + required: true + + - type: textarea + id: acceptance-criteria + attributes: + label: "๐ŸŽฏ Acceptance Criteria" + description: What must happen for this feature to be considered structurally functional? + placeholder: | + - [ ] Criteria 1 (e.g., Clicking 'Export' generates a CSV file download) + - [ ] Criteria 2 + - [ ] Criteria 3 + validations: + required: true + + - type: textarea + id: out-of-scope + attributes: + label: "๐Ÿšซ Out of Scope" + description: What is explicitly not included in this story? + placeholder: | + - [ ] Item 1 + - [ ] Item 2 + validations: + required: false + + - type: checkboxes + id: definition-of-done-quality + attributes: + label: "๐Ÿ Definition of Done โ€” ๐Ÿ› ๏ธ Quality & Testing" + options: + - label: Code has been peer-reviewed for bugs and vulnerabilities. + - label: Proper testing has been completed and passes (Unit, Integration, E2E via GitHub Actions). + - label: The feature has been demonstrated/validated successfully in the target environment. + + - type: checkboxes + id: definition-of-done-docs + attributes: + label: "๐Ÿ Definition of Done โ€” ๐Ÿ“ Architecture & Docs" + options: + - label: Usage documentation or changelog updated (if user-facing changes introduced). + - label: Local ADR written and verified by Tech Lead if technical architecture deviated. + - label: Any newly introduced technical debt has been logged as a GitHub issue. diff --git a/.github/workflows/ci_checks.yml b/.github/workflows/ci_checks.yml index dcaed20..34036fc 100644 --- a/.github/workflows/ci_checks.yml +++ b/.github/workflows/ci_checks.yml @@ -20,3 +20,4 @@ jobs: permissions: contents: read issues: read + pull-requests: read diff --git a/.github/workflows/ci_dependencies.yml b/.github/workflows/ci_dependencies.yml index f0a514e..876eb00 100644 --- a/.github/workflows/ci_dependencies.yml +++ b/.github/workflows/ci_dependencies.yml @@ -4,6 +4,8 @@ name: Dependencies # Orchestrates dependency review for all PRs and dependabot-specific # processing: structured PR comments with review data and auto-approval # for safe dependency updates (non-major, 24h+ release age, no vulnerabilities). +# Org-owned dependencies (same GitHub org) skip the release age gate and +# get auto-merge enabled for patch/minor updates. # -------------------------------------------------------------------------- on: @@ -33,12 +35,12 @@ jobs: comment_on_dependabot_prs: name: Dependabot Comment - if: github.actor == 'dependabot[bot]' + if: github.event.pull_request.user.login == 'dependabot[bot]' runs-on: ubuntu-latest needs: [call_deps_reviewer, call_dependabot_reviewer] permissions: issues: read - pull-requests: write # Necessary to write a comment + pull-requests: write # Necessary to write a comment steps: - name: Comment from Dependabot Reviewer uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0 @@ -49,6 +51,7 @@ jobs: DEP_NAME: ${{ needs.call_dependabot_reviewer.outputs.dep_name }} DEP_VERSION: ${{ needs.call_dependabot_reviewer.outputs.dep_version }} RELEASE_AGE_HOURS: ${{ needs.call_dependabot_reviewer.outputs.release_age_hours }} + IS_ORG_OWNED: ${{ needs.call_dependabot_reviewer.outputs.is_org_owned }} with: issue-number: ${{ github.event.pull_request.number }} edit-mode: replace @@ -62,9 +65,10 @@ jobs: | **Dependencies Review** | **${{ env.REVIEW_CONCLUSION }}** | [View logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) | | **Calculated Risk** | **${{ env.RISK_LEVEL }}** | `${{ env.DEP_NAME }}` v${{ env.DEP_VERSION }} | | **Release Age** | **${{ (env.RELEASE_AGE_HOURS == '-1' || env.RELEASE_AGE_HOURS == '') && 'unknown' || format('{0}h', env.RELEASE_AGE_HOURS) }}** | ${{ (env.RELEASE_AGE_HOURS == '-1' || env.RELEASE_AGE_HOURS == '') && 'Release date unavailable โ€” manual review required' || format('Released {0} hours ago', env.RELEASE_AGE_HOURS) }} | + | **Ownership** | **${{ env.IS_ORG_OWNED == 'true' && 'org-owned' || 'third-party' }}** | ${{ env.IS_ORG_OWNED == 'true' && 'Same organization โ€” trusted source' || 'External dependency' }} | | **Dependency Usage** | ${{ env.UPDATES_COUNT == '0' && 'unavailable' || format('{0} repos', env.UPDATES_COUNT) }} | Informational only โ€” does not affect approval | - **Auto-approval:** ${{ env.RISK_LEVEL != 'high' && env.REVIEW_CONCLUSION == 'success' && env.RELEASE_AGE_HOURS != '-1' && fromJSON(env.RELEASE_AGE_HOURS) >= fromJSON(env.MIN_RELEASE_AGE_HOURS) && 'โœ… Approved' || 'โณ Manual review required' }} + **Auto-approval:** ${{ (env.IS_ORG_OWNED == 'true' && env.RISK_LEVEL != 'high' && env.REVIEW_CONCLUSION == 'success') && 'โœ… Approved + auto-merge requested (org-owned)' || (env.RISK_LEVEL != 'high' && env.REVIEW_CONCLUSION == 'success' && env.RELEASE_AGE_HOURS != '-1' && fromJSON(env.RELEASE_AGE_HOURS) >= fromJSON(env.MIN_RELEASE_AGE_HOURS)) && 'โœ… Approved' || 'โณ Manual review required' }} --- @@ -77,30 +81,58 @@ jobs: approve_dependabot_prs: name: Dependabot Auto-approve - if: github.actor == 'dependabot[bot]' + if: github.event.pull_request.user.login == 'dependabot[bot]' runs-on: ubuntu-latest needs: [call_deps_reviewer, call_dependabot_reviewer] permissions: - pull-requests: write # Necessary to approve a PR + contents: write # Required for gh pr merge --auto + pull-requests: write # Required to approve a PR steps: - name: Auto-approve if Confident + id: auto_approve if: >- - needs.call_dependabot_reviewer.outputs.risk_level != 'high' && - needs.call_deps_reviewer.outputs.review_conclusion == 'success' && - needs.call_dependabot_reviewer.outputs.release_age_hours != '-1' && - fromJSON(needs.call_dependabot_reviewer.outputs.release_age_hours) >= fromJSON(env.MIN_RELEASE_AGE_HOURS) + (needs.call_dependabot_reviewer.outputs.risk_level != 'high' && + needs.call_deps_reviewer.outputs.review_conclusion == 'success' && + needs.call_dependabot_reviewer.outputs.release_age_hours != '-1' && + fromJSON(needs.call_dependabot_reviewer.outputs.release_age_hours) >= fromJSON(env.MIN_RELEASE_AGE_HOURS)) + || + (needs.call_dependabot_reviewer.outputs.is_org_owned == 'true' && + needs.call_dependabot_reviewer.outputs.risk_level != 'high' && + needs.call_deps_reviewer.outputs.review_conclusion == 'success') uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + env: + RISK_LEVEL: ${{ needs.call_dependabot_reviewer.outputs.risk_level }} + REVIEW_CONCLUSION: ${{ needs.call_deps_reviewer.outputs.review_conclusion }} + RELEASE_AGE_HOURS: ${{ needs.call_dependabot_reviewer.outputs.release_age_hours }} + IS_ORG_OWNED: ${{ needs.call_dependabot_reviewer.outputs.is_org_owned }} with: script: | - const risk = '${{ needs.call_dependabot_reviewer.outputs.risk_level }}'; - const review = '${{ needs.call_deps_reviewer.outputs.review_conclusion }}'; - const releaseAge = '${{ needs.call_dependabot_reviewer.outputs.release_age_hours }}'; + const risk = process.env.RISK_LEVEL; + const review = process.env.REVIEW_CONCLUSION; + const releaseAge = process.env.RELEASE_AGE_HOURS; + const isOrgOwned = process.env.IS_ORG_OWNED; + const ownership = isOrgOwned === 'true' ? 'org-owned' : 'third-party'; + const ageInfo = isOrgOwned === 'true' ? 'skipped (org-owned)' : `${releaseAge}h`; github.rest.pulls.createReview({ owner: context.repo.owner, repo: context.repo.repo, pull_number: context.issue.number, event: 'APPROVE', - body: `Automatically approved: risk=${risk}, review=${review}, release_age=${releaseAge}h.` + body: `Automatically approved: risk=${risk}, review=${review}, ownership=${ownership}, release_age=${ageInfo}.` }); - console.log(`Dependabot PR approved: risk=${risk}, review=${review}, release_age=${releaseAge}h`); + console.log(`Dependabot PR approved: risk=${risk}, review=${review}, ownership=${ownership}, release_age=${ageInfo}`); + + - name: Enable Auto-merge for Org-owned + if: >- + steps.auto_approve.outcome == 'success' && + needs.call_dependabot_reviewer.outputs.is_org_owned == 'true' + continue-on-error: true + env: + GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + run: | + echo "Enabling auto-merge for org-owned dependency..." + gh pr merge "${{ github.event.pull_request.number }}" \ + --auto --squash \ + --repo "${{ github.repository }}" + echo "Auto-merge enabled successfully." diff --git a/.github/workflows/ci_scheduled.yml b/.github/workflows/ci_scheduled.yml index 40345fe..e84b7ec 100644 --- a/.github/workflows/ci_scheduled.yml +++ b/.github/workflows/ci_scheduled.yml @@ -2,7 +2,7 @@ name: Scheduled Jobs on: schedule: - - cron: '0 0 * * *' + - cron: "0 0 * * *" permissions: contents: read @@ -15,7 +15,7 @@ jobs: name: OSV-Scanner and Scorecards permissions: contents: read - actions: read # Required to upload SARIF file to CodeQL. See: https://github.com/github/codeql-action/issues/2117 - security-events: write # Require writing security events to upload SARIF file to security tab - id-token: write # Needed to access GitHub's OIDC token which verifies the authenticity of the result when publishing it. + actions: read # Required to upload SARIF file to CodeQL. See: https://github.com/github/codeql-action/issues/2117 + security-events: write # Require writing security events to upload SARIF file to security tab + id-token: write # Needed to access GitHub's OIDC token which verifies the authenticity of the result when publishing it. uses: complytime/org-infra/.github/workflows/reusable_scheduled.yml@0c784711926c9864f027ec565fd7c06a382d80f8 # v0.7.1 diff --git a/.github/workflows/ci_security.yml b/.github/workflows/ci_security.yml index 629ee75..b771491 100644 --- a/.github/workflows/ci_security.yml +++ b/.github/workflows/ci_security.yml @@ -26,6 +26,7 @@ jobs: with: # OSV focuses on known CVEs in dependencies; Trivy adds broader coverage enable_trivy_source: false + trivy_ignorefile: '' call_reusable_security: name: OpenSSF Scorecards diff --git a/.golangci.yml b/.golangci.yml index 89c3006..06716f8 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,11 +1,8 @@ version: "2" -run: - skip-dirs: - - vendor linters: - default: standard # https://golangci-lint.run/usage/linters/#enabled-by-default + default: standard # https://golangci-lint.run/usage/linters/#enabled-by-default enable: - - gosec # Security checks for Go code + - gosec # Security checks for Go code exclusions: generated: lax presets: @@ -15,6 +12,6 @@ linters: - std-error-handling formatters: enable: - - goimports # Checks import statements are formatted + - goimports # Checks import statements are formatted exclusions: generated: lax diff --git a/.mega-linter.yml b/.mega-linter.yml index cfeaee1..82d6f51 100644 --- a/.mega-linter.yml +++ b/.mega-linter.yml @@ -1,7 +1,16 @@ # https://megalinter.io/latest/supported-linters/ +# .opencode and .claude contain AI agent/skill definitions with intentional +# formatting patterns that conflict with markdownlint and yamllint rules. +# Other scanners (grype, Trivy, OSV-Scanner, REPOSITORY_BETTERLEAKS) still +# cover these paths -- only MegaLinter's style linters are excluded. ADDITIONAL_EXCLUDED_DIRECTORIES: - vendor + - .opencode + - .claude +MARKDOWN_MARKDOWNLINT_FILTER_REGEX_EXCLUDE: "(vendor/)" +PROTOBUF_PROTOLINT_FILTER_REGEX_EXCLUDE: "(vendor/)" ENABLE_LINTERS: + - ACTION_ZIZMOR - ACTION_ACTIONLINT - ANSIBLE_ANSIBLE_LINT - BASH_SHELLCHECK @@ -10,7 +19,7 @@ ENABLE_LINTERS: - MARKDOWN_MARKDOWNLINT - PYTHON_RUFF - PROTOBUF_PROTOLINT - - REPOSITORY_GITLEAKS + - REPOSITORY_BETTERLEAKS - REPOSITORY_KICS - YAML_YAMLLINT REPOSITORY_KICS_ARGUMENTS: "--fail-on high" diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..7157d04 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,20 @@ +# Security Policy + +## Reporting a Vulnerability + +To report a security vulnerability, either: + +1. **GitHub Private Vulnerability Reporting** (preferred): Navigate to the + Security tab on the affected repository, click "Advisories", then + "Report a vulnerability". See the + [GitHub guide](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability) + for details. + +2. **Email**: Send a report to `complytime-security@redhat.com` with a + description of the issue and the affected project(s). + +Do NOT open a public GitHub issue for security vulnerabilities. + +For the full organization-wide security policy, including what to include +in a report, public disclosure process, and supported versions, see the +[ComplyTime Security Policy](https://github.com/complytime/community/blob/main/SECURITY.md).