chore: import upstream snapshot with attribution
Check engine pin consistency / Dockerfile / CI pin consistency (push) Successful in 8s
Sirius CI/CD Pipeline / Detect Changes (push) Successful in 23s
Validate Docker Configuration / Validate Docker Compose Configuration (push) Successful in 47s
Sirius CI/CD Pipeline / Build API (${{ matrix.platform }}) (push) Has been cancelled
Sirius CI/CD Pipeline / Build UI (${{ matrix.platform }}) (push) Has been cancelled
Sirius CI/CD Pipeline / Merge Engine Manifest (push) Has been cancelled
Sirius CI/CD Pipeline / Merge API Manifest (push) Has been cancelled
Sirius CI/CD Pipeline / Merge UI Manifest (push) Has been cancelled
Sirius CI/CD Pipeline / Build Engine (${{ matrix.platform }}) (push) Has been cancelled
Sirius CI/CD Pipeline / Build Infra (${{ matrix.service }}, ${{ matrix.platform }}) (push) Has been cancelled
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-postgres) (push) Has been cancelled
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-rabbitmq) (push) Has been cancelled
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-valkey) (push) Has been cancelled
Sirius CI/CD Pipeline / Integration Test (push) Has been cancelled
Sirius CI/CD Pipeline / Public Stack Contract (push) Has been cancelled
Sirius CI/CD Pipeline / Dispatch Demo Deployment (sirius-demo branch) (push) Has been cancelled
Sirius CI/CD Pipeline / Dispatch Demo Canary (main branch) (push) Has been cancelled
Sirius CI/CD Pipeline / Guard Registry Namespace (push) Has been cancelled
Check engine pin consistency / Dockerfile / CI pin consistency (push) Successful in 8s
Sirius CI/CD Pipeline / Detect Changes (push) Successful in 23s
Validate Docker Configuration / Validate Docker Compose Configuration (push) Successful in 47s
Sirius CI/CD Pipeline / Build API (${{ matrix.platform }}) (push) Has been cancelled
Sirius CI/CD Pipeline / Build UI (${{ matrix.platform }}) (push) Has been cancelled
Sirius CI/CD Pipeline / Merge Engine Manifest (push) Has been cancelled
Sirius CI/CD Pipeline / Merge API Manifest (push) Has been cancelled
Sirius CI/CD Pipeline / Merge UI Manifest (push) Has been cancelled
Sirius CI/CD Pipeline / Build Engine (${{ matrix.platform }}) (push) Has been cancelled
Sirius CI/CD Pipeline / Build Infra (${{ matrix.service }}, ${{ matrix.platform }}) (push) Has been cancelled
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-postgres) (push) Has been cancelled
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-rabbitmq) (push) Has been cancelled
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-valkey) (push) Has been cancelled
Sirius CI/CD Pipeline / Integration Test (push) Has been cancelled
Sirius CI/CD Pipeline / Public Stack Contract (push) Has been cancelled
Sirius CI/CD Pipeline / Dispatch Demo Deployment (sirius-demo branch) (push) Has been cancelled
Sirius CI/CD Pipeline / Dispatch Demo Canary (main branch) (push) Has been cancelled
Sirius CI/CD Pipeline / Guard Registry Namespace (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
name: Auth or 401 Issue
|
||||
description: Report API key drift, auth mismatches, and unauthorized responses.
|
||||
title: "[auth/401]: "
|
||||
labels:
|
||||
- status:needs-triage
|
||||
- type:bug
|
||||
- area:auth
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Use this form for `401` responses, API key mismatch, and auth surface incidents.
|
||||
This maps directly to the API key operations runbook.
|
||||
|
||||
- type: input
|
||||
id: endpoint
|
||||
attributes:
|
||||
label: Endpoint/Surface Affected
|
||||
placeholder: "e.g. /host/, tRPC scanner.getScanStatus, /api/v1/keys"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: symptom
|
||||
attributes:
|
||||
label: Primary Symptom
|
||||
options:
|
||||
- 401 on non-health API routes
|
||||
- UI cannot read/write through tRPC
|
||||
- scanner/agent submissions return 401
|
||||
- key rotation appears incomplete
|
||||
- unknown auth failure
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
id: runbook_checks
|
||||
attributes:
|
||||
label: Runbook Checks Completed
|
||||
options:
|
||||
- label: I verified `SIRIUS_API_KEY` is set and non-empty in all runtime services.
|
||||
required: true
|
||||
- label: I confirmed services are using the same active key (`sirius-api`, `sirius-ui`, `sirius-engine`).
|
||||
required: true
|
||||
- label: I re-ran installer and restarted services after any key changes.
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
id: evidence
|
||||
attributes:
|
||||
label: Diagnostics and Evidence
|
||||
description: Include key env checks and relevant logs.
|
||||
placeholder: |
|
||||
docker inspect sirius-api --format '{{range .Config.Env}}{{println .}}{{end}}' | rg '^SIRIUS_API_KEY='
|
||||
docker inspect sirius-ui --format '{{range .Config.Env}}{{println .}}{{end}}' | rg '^SIRIUS_API_KEY='
|
||||
docker inspect sirius-engine --format '{{range .Config.Env}}{{println .}}{{end}}' | rg '^SIRIUS_API_KEY='
|
||||
docker compose logs --no-color --tail=120 sirius-api sirius-ui sirius-engine
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: repro_steps
|
||||
attributes:
|
||||
label: Reproduction Steps
|
||||
placeholder: "Provide exact, minimal steps to reproduce."
|
||||
validations:
|
||||
required: true
|
||||
@@ -0,0 +1,60 @@
|
||||
name: Bug Report
|
||||
description: Report a reproducible defect in Sirius Scan.
|
||||
title: "[bug]: "
|
||||
labels:
|
||||
- status:needs-triage
|
||||
- type:bug
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for reporting a bug. Please provide enough detail for maintainers to reproduce quickly.
|
||||
|
||||
- type: input
|
||||
id: component
|
||||
attributes:
|
||||
label: Affected Component
|
||||
placeholder: "e.g. sirius-api, sirius-ui, scanner workflow, docker startup"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
placeholder: "e.g. v1.0.0, main, commit SHA"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: steps
|
||||
attributes:
|
||||
label: Reproduction Steps
|
||||
placeholder: |
|
||||
1. ...
|
||||
2. ...
|
||||
3. ...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: actual
|
||||
attributes:
|
||||
label: Actual Behavior
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: evidence
|
||||
attributes:
|
||||
label: Logs and Evidence
|
||||
description: Include command output, screenshots, and relevant logs.
|
||||
validations:
|
||||
required: true
|
||||
@@ -0,0 +1,11 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Community Support
|
||||
url: https://github.com/SiriusScan/Sirius/discussions
|
||||
about: Ask usage and architecture questions in Discussions.
|
||||
- name: Sirius Documentation
|
||||
url: https://sirius.opensecurity.com/docs/getting-started/installation
|
||||
about: Start here for setup and troubleshooting guidance.
|
||||
- name: Security Policy
|
||||
url: https://github.com/SiriusScan/Sirius/security/policy
|
||||
about: Report sensitive vulnerabilities through private security channels.
|
||||
@@ -0,0 +1,49 @@
|
||||
name: Dev Overlay / Compose Override Issue
|
||||
description: Report local dev overlay, mount shadowing, and compose override problems.
|
||||
title: "[dev-overlay]: "
|
||||
labels:
|
||||
- status:needs-triage
|
||||
- type:bug
|
||||
- area:compose-dev
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Use this form for `docker-compose.dev.yaml` usage issues, mount shadowing, and missing infra services.
|
||||
Reminder: dev compose is an override file and must be combined with base compose.
|
||||
|
||||
- type: checkboxes
|
||||
id: compose_usage
|
||||
attributes:
|
||||
label: Compose Command Validation
|
||||
options:
|
||||
- label: I used `docker compose -f docker-compose.yaml -f docker-compose.dev.yaml up -d` (not dev file alone).
|
||||
required: true
|
||||
- label: `docker compose -f docker-compose.yaml -f docker-compose.dev.yaml config --quiet` succeeds.
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: command_history
|
||||
attributes:
|
||||
label: Exact Commands Run
|
||||
placeholder: "Paste exact commands in order."
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: symptom
|
||||
attributes:
|
||||
label: What Broke?
|
||||
placeholder: "e.g. missing postgres/rabbitmq/valkey, mount shadowing, prisma init issues."
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Logs / Compose Output
|
||||
placeholder: |
|
||||
docker compose ps
|
||||
docker compose logs --no-color --tail=120 sirius-ui sirius-api sirius-engine
|
||||
validations:
|
||||
required: true
|
||||
@@ -0,0 +1,54 @@
|
||||
name: Feature Request
|
||||
description: Propose a new capability or improvement for Sirius Scan.
|
||||
title: "[feature]: "
|
||||
labels:
|
||||
- status:needs-triage
|
||||
- type:enhancement
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Use this form to propose features with clear problem framing and success criteria.
|
||||
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: Problem Statement
|
||||
description: What user or operator problem are you trying to solve?
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: proposal
|
||||
attributes:
|
||||
label: Proposed Solution
|
||||
description: Describe the preferred implementation or behavior.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Alternatives Considered
|
||||
description: List alternatives and why they were not chosen.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: dropdown
|
||||
id: impact
|
||||
attributes:
|
||||
label: Expected Impact
|
||||
options:
|
||||
- low
|
||||
- medium
|
||||
- high
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: success
|
||||
attributes:
|
||||
label: Success Criteria
|
||||
description: What outcomes or metrics indicate this feature is complete?
|
||||
validations:
|
||||
required: true
|
||||
@@ -0,0 +1,77 @@
|
||||
name: Install or Startup Failure
|
||||
description: Report stack startup failures, restart loops, and first-run issues.
|
||||
title: "[install/startup]: "
|
||||
labels:
|
||||
- status:needs-triage
|
||||
- type:bug
|
||||
- area:installer-secrets
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Use this form when Sirius fails to start or continuously restarts.
|
||||
Include required diagnostics so maintainers can triage without back-and-forth.
|
||||
|
||||
- type: dropdown
|
||||
id: install_mode
|
||||
attributes:
|
||||
label: Install/Run Mode
|
||||
description: Which compose mode are you using?
|
||||
options:
|
||||
- Standard (`docker compose up -d`)
|
||||
- Dev overlay (`-f docker-compose.yaml -f docker-compose.dev.yaml`)
|
||||
- Prod overlay (`-f docker-compose.yaml -f docker-compose.prod.yaml`)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Sirius Version / Image Tag
|
||||
placeholder: "e.g. v1.0.0, latest, or image digest"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: host
|
||||
attributes:
|
||||
label: Host OS + Docker Version
|
||||
placeholder: "e.g. macOS 15.2, Docker 27.x"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
id: installer_check
|
||||
attributes:
|
||||
label: Installer-First Validation
|
||||
options:
|
||||
- label: I ran `docker compose -f docker-compose.installer.yaml run --rm sirius-installer` before starting.
|
||||
required: true
|
||||
- label: I confirmed `docker compose config --quiet` renders successfully with required secrets.
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant Logs (last 100 lines)
|
||||
description: Include logs from `sirius-api`, `sirius-engine`, and `sirius-ui`.
|
||||
placeholder: |
|
||||
docker compose logs --no-color --tail=100 sirius-api sirius-engine sirius-ui
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
placeholder: "What did you expect to happen?"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: observed
|
||||
attributes:
|
||||
label: Observed Behavior
|
||||
placeholder: "What happened instead? Include exact errors."
|
||||
validations:
|
||||
required: true
|
||||
@@ -0,0 +1,65 @@
|
||||
name: Security Report (Non-sensitive)
|
||||
description: Report security hardening gaps suitable for public tracking.
|
||||
title: "[security]: "
|
||||
labels:
|
||||
- status:needs-triage
|
||||
- type:security
|
||||
- sev:high
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Use this form for non-sensitive security issues appropriate for public discussion.
|
||||
For sensitive vulnerabilities, use GitHub Security Advisories instead.
|
||||
|
||||
- type: checkboxes
|
||||
id: sensitivity
|
||||
attributes:
|
||||
label: Sensitivity Check
|
||||
options:
|
||||
- label: This report does not include exploit details or sensitive data.
|
||||
required: true
|
||||
- label: I understand sensitive issues must be reported privately.
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: surface
|
||||
attributes:
|
||||
label: Security Surface
|
||||
options:
|
||||
- Auth / API key validation
|
||||
- Session / NextAuth
|
||||
- CORS / headers
|
||||
- RabbitMQ / queue integrity
|
||||
- Deployment / secrets handling
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: impact
|
||||
attributes:
|
||||
label: Estimated Impact
|
||||
options:
|
||||
- critical
|
||||
- high
|
||||
- medium
|
||||
- low
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Issue Description
|
||||
placeholder: "Describe the security concern and affected components."
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: reproduction
|
||||
attributes:
|
||||
label: Reproduction / Validation
|
||||
placeholder: "Steps, logs, and relevant hardening/security-suite evidence."
|
||||
validations:
|
||||
required: true
|
||||
@@ -0,0 +1,62 @@
|
||||
name: Windows / WSL2 Issue
|
||||
description: Report Windows-specific startup and script problems (including CRLF handling).
|
||||
title: "[windows-wsl2]: "
|
||||
labels:
|
||||
- status:needs-triage
|
||||
- type:bug
|
||||
- platform:windows
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Sirius supports Windows via WSL2. Use this form for CRLF, shell script, and path/mount issues.
|
||||
|
||||
- type: input
|
||||
id: windows_version
|
||||
attributes:
|
||||
label: Windows + WSL Version
|
||||
placeholder: "e.g. Windows 11 24H2, WSL2 Ubuntu 24.04"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: docker_desktop
|
||||
attributes:
|
||||
label: Docker Desktop Version
|
||||
placeholder: "e.g. 4.x"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: issue_class
|
||||
attributes:
|
||||
label: Issue Class
|
||||
options:
|
||||
- CRLF / shell script execution
|
||||
- bind mount behavior
|
||||
- path translation
|
||||
- networking/port behavior
|
||||
- unknown
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: evidence
|
||||
attributes:
|
||||
label: Evidence
|
||||
placeholder: |
|
||||
Include:
|
||||
- exact error text
|
||||
- command output
|
||||
- relevant logs
|
||||
- whether files were cloned in Windows FS or WSL FS
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: repro
|
||||
attributes:
|
||||
label: Reproduction Steps
|
||||
placeholder: "Minimal steps from clone to failure."
|
||||
validations:
|
||||
required: true
|
||||
@@ -0,0 +1,77 @@
|
||||
# Organization Profile Rollout Checklist
|
||||
|
||||
This checklist publishes the organization profile using the content in `.github/profile/README.md`.
|
||||
|
||||
## 0. Prepare aesthetic baseline (brand/story)
|
||||
|
||||
Before publishing, confirm profile content has:
|
||||
|
||||
1. A short mission statement in the first paragraph.
|
||||
2. A clear "what we build" section for first-time visitors.
|
||||
3. A "start here" section with docs, install, API, and security links.
|
||||
4. Repository blurbs that use consistent tone and sentence structure.
|
||||
5. Contributor entry points (`CONTRIBUTING.md`, `SUPPORT.md`, Discussions).
|
||||
|
||||
## 1. Create the organization profile repository
|
||||
|
||||
1. In the `SiriusScan` organization, create a **public** repository named `.github`.
|
||||
2. Copy `.github/profile/README.md` from this repository into the new repository at `profile/README.md`.
|
||||
3. Commit and push.
|
||||
|
||||
## 2. Configure organization branding
|
||||
|
||||
1. Open organization settings and upload:
|
||||
- Organization avatar (square logo)
|
||||
- Optional profile banner image
|
||||
2. Set a concise organization description aligned with the README mission statement.
|
||||
3. Ensure links are set for website and documentation.
|
||||
|
||||
## 3. Configure public pinned repositories
|
||||
|
||||
Pin up to six repositories in this order (this is also the brand narrative order):
|
||||
|
||||
1. `Sirius`
|
||||
2. `go-api`
|
||||
3. `app-scanner`
|
||||
4. `app-agent`
|
||||
5. `pingpp`
|
||||
6. `website`
|
||||
|
||||
## 4. Standardize repository metadata
|
||||
|
||||
For each pinned repository:
|
||||
|
||||
1. Update repository description for consistent language and tone.
|
||||
2. Add GitHub topics (for example: `security`, `vulnerability-scanner`, `devsecops`, `golang`, `nextjs` as applicable).
|
||||
3. Verify homepage URL points to product docs or website.
|
||||
|
||||
Recommended descriptions and links:
|
||||
|
||||
| Repository | Description | Homepage | Suggested topics |
|
||||
| --- | --- | --- | --- |
|
||||
| `Sirius` | Core platform, orchestration, docs, and deployment baseline for SiriusScan. | `https://sirius.opensecurity.com/docs/getting-started/quick-start` | `security`, `devsecops`, `vulnerability-scanner`, `docker`, `nextjs` |
|
||||
| `go-api` | Backend API services for platform operations and integrations. | `https://sirius.opensecurity.com/docs/api/rest/authentication` | `golang`, `api`, `security`, `backend` |
|
||||
| `app-scanner` | Scanning execution service for discovery and vulnerability collection. | `https://sirius.opensecurity.com/docs/getting-started/installation` | `scanner`, `security`, `golang`, `automation` |
|
||||
| `app-agent` | Agent runtime for distributed scanning and remote execution workflows. | `https://sirius.opensecurity.com/docs/getting-started/installation` | `agent`, `golang`, `security`, `distributed-systems` |
|
||||
| `pingpp` | Network diagnostics and connectivity support utilities. | `https://sirius.opensecurity.com/docs/getting-started/installation` | `networking`, `golang`, `diagnostics`, `security` |
|
||||
| `website` | Public website and product-facing content for SiriusScan. | `https://sirius.opensecurity.com` | `website`, `nextjs`, `security`, `docs` |
|
||||
|
||||
## 5. Enable community and trust signals
|
||||
|
||||
1. Enable Discussions where appropriate.
|
||||
2. Confirm each repository has:
|
||||
- `README.md`
|
||||
- `CONTRIBUTING.md`
|
||||
- `SECURITY.md`
|
||||
- `CODE_OF_CONDUCT.md`
|
||||
- `LICENSE`
|
||||
3. Confirm branch protection rules are enabled for default branches.
|
||||
|
||||
## 6. Publish quality check
|
||||
|
||||
Validate from a first-time visitor perspective:
|
||||
|
||||
1. Profile page communicates value in under 30 seconds.
|
||||
2. New contributors can find contribution and support paths quickly.
|
||||
3. Security reporting path is visible and private-report guidance is explicit.
|
||||
4. Pinned repositories feel cohesive and professionally described.
|
||||
@@ -0,0 +1,40 @@
|
||||
# SiriusScan Org Setup Status (Core-First)
|
||||
|
||||
This status note tracks implementation progress for the aesthetics + professional standards rollout.
|
||||
|
||||
## Completed in core repository (`Sirius`)
|
||||
|
||||
- Rewrote organization profile content in `.github/profile/README.md` with a brand/story-forward narrative and clear contributor entry points.
|
||||
- Expanded `.github/ORGANIZATION_PROFILE_SETUP.md` with:
|
||||
- aesthetic baseline checks
|
||||
- recommended metadata table (description/homepage/topics)
|
||||
- publish quality validation
|
||||
- Added advisory standards pack:
|
||||
- `.github/REPOSITORY_STANDARDS_ADVISORY.md`
|
||||
- Added reusable rollout checklist:
|
||||
- `.github/REPO_ROLLOUT_CHECKLIST.md`
|
||||
|
||||
## Verification summary
|
||||
|
||||
- First-time visitor clarity: improved through mission-first profile structure and explicit "Start Here" links.
|
||||
- Contributor journey: explicit links to contribution guide, discussions, and support paths are present.
|
||||
- Security reporting discoverability: security policy link remains prominent in profile and issue template config.
|
||||
- Reusability: standards and rollout docs are now available as a template for other repositories.
|
||||
|
||||
## Remaining manual actions (GitHub UI)
|
||||
|
||||
These items cannot be fully enforced from repository files alone and should be completed in organization/repository settings:
|
||||
|
||||
- Apply final organization description text in org settings.
|
||||
- Confirm pinned repositories in the specified narrative order.
|
||||
- Update per-repository metadata (description, topics, homepage) to match the recommended table.
|
||||
- Enable Discussions in repositories where community interaction is desired.
|
||||
- Review branch protection/rulesets and keep them advisory-first for this phase.
|
||||
|
||||
## Next rollout targets
|
||||
|
||||
- `go-api`
|
||||
- `app-scanner`
|
||||
- `app-agent`
|
||||
- `pingpp`
|
||||
- `website`
|
||||
@@ -0,0 +1,52 @@
|
||||
## Summary
|
||||
|
||||
Describe the problem this PR solves and why this approach was chosen.
|
||||
|
||||
## Change Type
|
||||
|
||||
- [ ] Bug fix
|
||||
- [ ] Feature
|
||||
- [ ] Refactor
|
||||
- [ ] Documentation
|
||||
- [ ] CI/CD or automation
|
||||
- [ ] Security hardening
|
||||
|
||||
## Scope
|
||||
|
||||
- [ ] `sirius-ui`
|
||||
- [ ] `sirius-api`
|
||||
- [ ] `sirius-engine`
|
||||
- [ ] Infrastructure (`postgres`, `rabbitmq`, `valkey`, compose)
|
||||
- [ ] Documentation
|
||||
- [ ] Other (describe below)
|
||||
|
||||
## Related Issue
|
||||
|
||||
Closes #
|
||||
|
||||
## Validation
|
||||
|
||||
- [ ] I ran required local validation for this change
|
||||
- [ ] I attached logs, screenshots, or output where relevant
|
||||
- [ ] I tested failure paths or edge cases where applicable
|
||||
- [ ] CI checks are expected to pass for this PR
|
||||
|
||||
## Security and Risk Review
|
||||
|
||||
- [ ] No security impact
|
||||
- [ ] Security impact reviewed and documented
|
||||
- [ ] Rollback steps are documented for risky operational changes
|
||||
|
||||
## Documentation
|
||||
|
||||
- [ ] No docs change needed
|
||||
- [ ] Updated `README.md`, `CONTRIBUTING.md`, `SECURITY.md`, or related docs
|
||||
- [ ] Added/updated issue templates or workflow docs
|
||||
|
||||
## Deployment Notes
|
||||
|
||||
List any operational notes (migrations, secret changes, compose changes, required order of deployment, etc.).
|
||||
|
||||
## Additional Context
|
||||
|
||||
Add anything reviewers should know (tradeoffs, follow-ups, known limitations).
|
||||
@@ -0,0 +1,78 @@
|
||||
# SiriusScan Repository Standards (Advisory v1)
|
||||
|
||||
This document defines recommended repository standards for SiriusScan projects.
|
||||
|
||||
The goal is consistency and professionalism without introducing blocking rules. Teams can adopt these recommendations incrementally.
|
||||
|
||||
## Scope
|
||||
|
||||
Applies to public SiriusScan repositories, starting with `Sirius` and then expanding to:
|
||||
|
||||
- `go-api`
|
||||
- `app-scanner`
|
||||
- `app-agent`
|
||||
- `pingpp`
|
||||
- `website`
|
||||
|
||||
## Recommended baseline artifacts
|
||||
|
||||
Each repository should include:
|
||||
|
||||
- `README.md`
|
||||
- `CONTRIBUTING.md`
|
||||
- `SECURITY.md`
|
||||
- `CODE_OF_CONDUCT.md`
|
||||
- `LICENSE`
|
||||
- `SUPPORT.md` (recommended for active external contribution)
|
||||
|
||||
## Issue and PR intake standards
|
||||
|
||||
Recommended defaults:
|
||||
|
||||
- Issue templates for bug reports and feature requests
|
||||
- A security-focused intake path with explicit private-report guidance
|
||||
- A PR template that captures:
|
||||
- problem statement
|
||||
- risk and validation evidence
|
||||
- docs and rollout notes
|
||||
|
||||
For repositories with low issue volume, start with minimal templates and expand later.
|
||||
|
||||
## Labels and triage hygiene
|
||||
|
||||
Recommended label taxonomy:
|
||||
|
||||
- `type:*` (for example: `type:bug`, `type:enhancement`, `type:security`)
|
||||
- `status:*` (for example: `status:needs-triage`, `status:blocked`, `status:ready`)
|
||||
- `sev:*` for risk level where relevant
|
||||
- domain labels for components only where maintainers need them
|
||||
|
||||
Recommended triage SLA:
|
||||
|
||||
- First maintainer response within 2 business days
|
||||
- Security-labeled issues reviewed as priority
|
||||
|
||||
## Metadata and discoverability
|
||||
|
||||
Each repository should have:
|
||||
|
||||
- A one-line description aligned with org voice
|
||||
- At least 4-6 relevant topics
|
||||
- A homepage URL to docs, API reference, or website
|
||||
- Optional Discussions enabled where community interaction is expected
|
||||
|
||||
## Review and CI expectations (advisory)
|
||||
|
||||
Recommended defaults (not hard-gated in this phase):
|
||||
|
||||
- At least one maintainer review before merge
|
||||
- CI should run on pull requests
|
||||
- Validation evidence included in PR description
|
||||
- Security-sensitive changes include rollback notes
|
||||
|
||||
## Adoption approach
|
||||
|
||||
1. Adopt standards in `Sirius` first.
|
||||
2. Reuse the rollout checklist in `.github/REPO_ROLLOUT_CHECKLIST.md`.
|
||||
3. Track deviations and repository-specific exceptions in the repo README or maintainer notes.
|
||||
4. Revisit after adoption to decide whether any standards should become required.
|
||||
@@ -0,0 +1,64 @@
|
||||
# SiriusScan Repository Rollout Checklist
|
||||
|
||||
Use this checklist to apply the core `Sirius` standards to other SiriusScan repositories.
|
||||
|
||||
Target repositories:
|
||||
|
||||
- `go-api`
|
||||
- `app-scanner`
|
||||
- `app-agent`
|
||||
- `pingpp`
|
||||
- `website`
|
||||
|
||||
## 1) Pre-check
|
||||
|
||||
- Confirm default branch and active maintainers.
|
||||
- Confirm repository is public or intended visibility is documented.
|
||||
- Confirm whether Discussions should be enabled for that repository.
|
||||
|
||||
## 2) Copy baseline artifacts
|
||||
|
||||
Copy and adapt from `Sirius`:
|
||||
|
||||
- `CONTRIBUTING.md`
|
||||
- `SECURITY.md`
|
||||
- `CODE_OF_CONDUCT.md`
|
||||
- `SUPPORT.md` (recommended)
|
||||
- `.github/PULL_REQUEST_TEMPLATE.md`
|
||||
- `.github/ISSUE_TEMPLATE/config.yml`
|
||||
- Relevant `.github/ISSUE_TEMPLATE/*.yml` files
|
||||
|
||||
## 3) Customize repository-specific content
|
||||
|
||||
Adjust per repository:
|
||||
|
||||
- Repository description (one clear sentence)
|
||||
- Homepage URL (docs, API reference, or website)
|
||||
- Topics (4-6 relevant tags)
|
||||
- README architecture and setup sections
|
||||
- Template wording for component names and troubleshooting paths
|
||||
|
||||
## 4) Labels and workflows
|
||||
|
||||
- Apply label taxonomy from `.github/labels.yml` where relevant.
|
||||
- Ensure issue triage workflow is compatible with current labels.
|
||||
- Keep CI and automation advisory-first in this phase (no new hard gates required).
|
||||
|
||||
## 5) Verification rubric (professional-ready)
|
||||
|
||||
A repository is considered ready when all checks below pass:
|
||||
|
||||
- Professional first impression from repo homepage
|
||||
- Clear contribution and support paths
|
||||
- Security reporting path is present and understandable
|
||||
- Issue and PR templates collect enough context for maintainers
|
||||
- Metadata (description/topics/homepage) is complete and coherent
|
||||
|
||||
## 6) Completion record
|
||||
|
||||
For each repository, record:
|
||||
|
||||
- Date completed
|
||||
- Maintainer reviewer
|
||||
- Deviations from baseline and rationale
|
||||
- Follow-up items
|
||||
@@ -0,0 +1,84 @@
|
||||
# Dependabot configuration for automatic dependency updates
|
||||
#
|
||||
# This configuration enables automated dependency updates for Go modules,
|
||||
# Docker images, and GitHub Actions. Dependabot will create PRs automatically
|
||||
# when new versions are available.
|
||||
#
|
||||
# See: https://docs.github.com/en/code-security/dependabot
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
# Go modules in sirius-api
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/sirius-api"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "06:00"
|
||||
timezone: "America/Los_Angeles"
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "go"
|
||||
- "sirius-api"
|
||||
commit-message:
|
||||
prefix: "chore(deps)"
|
||||
include: "scope"
|
||||
open-pull-requests-limit: 5
|
||||
reviewers:
|
||||
- "0sm0s1z"
|
||||
# Auto-merge minor and patch updates after tests pass
|
||||
versioning-strategy: increase
|
||||
|
||||
# Go modules in sirius-engine
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/sirius-engine"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "06:00"
|
||||
timezone: "America/Los_Angeles"
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "go"
|
||||
- "sirius-engine"
|
||||
commit-message:
|
||||
prefix: "chore(deps)"
|
||||
include: "scope"
|
||||
open-pull-requests-limit: 5
|
||||
reviewers:
|
||||
- "0sm0s1z"
|
||||
versioning-strategy: increase
|
||||
|
||||
# Docker images
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
time: "06:00"
|
||||
timezone: "America/Los_Angeles"
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "docker"
|
||||
commit-message:
|
||||
prefix: "chore(deps)"
|
||||
include: "scope"
|
||||
open-pull-requests-limit: 3
|
||||
reviewers:
|
||||
- "0sm0s1z"
|
||||
|
||||
# GitHub Actions
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
time: "06:00"
|
||||
timezone: "America/Los_Angeles"
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "github-actions"
|
||||
commit-message:
|
||||
prefix: "chore(deps)"
|
||||
include: "scope"
|
||||
open-pull-requests-limit: 3
|
||||
reviewers:
|
||||
- "0sm0s1z"
|
||||
@@ -0,0 +1,68 @@
|
||||
area:ui:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "sirius-ui/**"
|
||||
|
||||
area:api:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "sirius-api/**"
|
||||
|
||||
area:engine:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "sirius-engine/**"
|
||||
|
||||
area:compose-dev:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "docker-compose.dev.yaml"
|
||||
- "docker-compose.override.yaml"
|
||||
- "scripts/dev-setup.sh"
|
||||
|
||||
area:compose-prod:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "docker-compose.prod.yaml"
|
||||
- ".github/workflows/deploy.yml"
|
||||
|
||||
area:installer-secrets:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "docker-compose.installer.yaml"
|
||||
- ".env.production.example"
|
||||
- "documentation/dev/architecture/ADR.startup-secrets-model.md"
|
||||
- "documentation/dev/operations/README.api-key-operations.md"
|
||||
|
||||
area:auth:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "sirius-ui/src/server/auth.ts"
|
||||
- "sirius-ui/src/server/api/**"
|
||||
- "sirius-api/**/middleware/**"
|
||||
- "documentation/dev/architecture/README.auth-surface-matrix.md"
|
||||
|
||||
area:rabbitmq:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "sirius-rabbitmq/**"
|
||||
- "**/*rabbitmq*"
|
||||
|
||||
area:postgres:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "sirius-postgres/**"
|
||||
- "**/*prisma*"
|
||||
- "**/*migration*"
|
||||
|
||||
area:valkey:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "**/*valkey*"
|
||||
- "**/*redis*"
|
||||
|
||||
type:docs:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "documentation/**"
|
||||
- "README.md"
|
||||
@@ -0,0 +1,104 @@
|
||||
- name: "status:needs-triage"
|
||||
color: "FBCA04"
|
||||
description: "New issue or PR requires maintainer triage."
|
||||
- name: "status:needs-info"
|
||||
color: "D4C5F9"
|
||||
description: "Reporter must provide missing diagnostics or reproduction details."
|
||||
- name: "status:repro-ready"
|
||||
color: "C2E0C6"
|
||||
description: "Issue includes sufficient details for reproducible investigation."
|
||||
- name: "status:confirmed"
|
||||
color: "0E8A16"
|
||||
description: "Maintainer has reproduced or validated the issue."
|
||||
- name: "status:in-progress"
|
||||
color: "1D76DB"
|
||||
description: "A maintainer is actively implementing or validating a fix."
|
||||
- name: "status:blocked"
|
||||
color: "B60205"
|
||||
description: "Work is blocked by dependency, environment, or external input."
|
||||
- name: "status:ready-to-merge"
|
||||
color: "5319E7"
|
||||
description: "PR has required evidence and is waiting final merge decision."
|
||||
- name: "status:done"
|
||||
color: "0E8A16"
|
||||
description: "Issue has been resolved and closed."
|
||||
|
||||
- name: "type:bug"
|
||||
color: "D73A4A"
|
||||
description: "Behavior does not match expected function."
|
||||
- name: "type:enhancement"
|
||||
color: "A2EEEF"
|
||||
description: "Improvement to existing behavior or workflow."
|
||||
- name: "type:security"
|
||||
color: "B60205"
|
||||
description: "Security behavior, hardening, or vulnerability concern."
|
||||
- name: "type:docs"
|
||||
color: "0075CA"
|
||||
description: "Documentation updates or gaps."
|
||||
- name: "type:question"
|
||||
color: "D876E3"
|
||||
description: "Clarification or support question."
|
||||
|
||||
- name: "size/XS"
|
||||
color: "0E8A16"
|
||||
description: "Small PR with very low review complexity."
|
||||
- name: "size/S"
|
||||
color: "1D76DB"
|
||||
description: "Small PR with low review complexity."
|
||||
- name: "size/M"
|
||||
color: "FBCA04"
|
||||
description: "Medium PR with moderate review complexity."
|
||||
- name: "size/L"
|
||||
color: "D93F0B"
|
||||
description: "Large PR with high review complexity."
|
||||
- name: "size/XL"
|
||||
color: "B60205"
|
||||
description: "Very large PR; consider splitting into smaller changes."
|
||||
|
||||
- name: "area:installer-secrets"
|
||||
color: "F9D0C4"
|
||||
description: "Installer-first flow, startup contract, or runtime secrets."
|
||||
- name: "area:compose-dev"
|
||||
color: "F9D0C4"
|
||||
description: "Development overlay compose behavior and local mounts."
|
||||
- name: "area:compose-prod"
|
||||
color: "F9D0C4"
|
||||
description: "Production compose overlay behavior and runtime settings."
|
||||
- name: "area:ui"
|
||||
color: "C5DEF5"
|
||||
description: "sirius-ui frontend and server-side API bridge."
|
||||
- name: "area:api"
|
||||
color: "C5DEF5"
|
||||
description: "sirius-api routes, middleware, and API behavior."
|
||||
- name: "area:engine"
|
||||
color: "C5DEF5"
|
||||
description: "sirius-engine scanning, gRPC, and orchestration behavior."
|
||||
- name: "area:rabbitmq"
|
||||
color: "C5DEF5"
|
||||
description: "Queue durability, routing, and consumer behavior."
|
||||
- name: "area:postgres"
|
||||
color: "C5DEF5"
|
||||
description: "Database schema, connection, and persistence concerns."
|
||||
- name: "area:valkey"
|
||||
color: "C5DEF5"
|
||||
description: "Valkey cache/key lifecycle behavior."
|
||||
- name: "area:auth"
|
||||
color: "C5DEF5"
|
||||
description: "Authentication, API key validation, and auth surfaces."
|
||||
|
||||
- name: "sev:critical"
|
||||
color: "B60205"
|
||||
description: "Security/data-loss/system integrity risk requiring immediate response."
|
||||
- name: "sev:high"
|
||||
color: "D93F0B"
|
||||
description: "System unusable or major reliability break."
|
||||
- name: "sev:medium"
|
||||
color: "FBCA04"
|
||||
description: "Substantial issue with workaround available."
|
||||
- name: "sev:low"
|
||||
color: "0E8A16"
|
||||
description: "Minor issue or paper-cut with low immediate risk."
|
||||
|
||||
- name: "platform:windows"
|
||||
color: "BFDADC"
|
||||
description: "Issue specific to Windows/WSL2 environments."
|
||||
@@ -0,0 +1,37 @@
|
||||
# SiriusScan
|
||||
|
||||
SiriusScan is an open-source security engineering platform for teams that want continuous visibility, faster risk triage, and practical remediation workflows.
|
||||
|
||||
We build security tooling for real operators and developers: discover assets, identify vulnerabilities, prioritize what matters, and integrate security work into day-to-day delivery.
|
||||
|
||||
## What We Build
|
||||
|
||||
- Continuous discovery and scanning across hosts, services, and infrastructure
|
||||
- Vulnerability intelligence and risk prioritization using actionable severity context
|
||||
- Operational workflows for remediation tracking and security posture reporting
|
||||
- API-first and automation-friendly components for modern DevSecOps pipelines
|
||||
|
||||
## Start Here
|
||||
|
||||
- Quick start: <https://sirius.opensecurity.com/docs/getting-started/quick-start>
|
||||
- Installation: <https://sirius.opensecurity.com/docs/getting-started/installation>
|
||||
- API docs: <https://sirius.opensecurity.com/docs/api/rest/authentication>
|
||||
- Security policy: <https://github.com/SiriusScan/Sirius/security/policy>
|
||||
- Project discussions: <https://github.com/SiriusScan/Sirius/discussions>
|
||||
|
||||
## Core Repositories
|
||||
|
||||
- [`Sirius`](https://github.com/SiriusScan/Sirius) - Core platform, orchestration, documentation, and deployment baseline
|
||||
- [`go-api`](https://github.com/SiriusScan/go-api) - Backend API services for integrations and platform operations
|
||||
- [`app-scanner`](https://github.com/SiriusScan/app-scanner) - Scanning execution service for discovery and vulnerability collection
|
||||
- [`app-agent`](https://github.com/SiriusScan/app-agent) - Agent runtime for distributed scanning and remote execution patterns
|
||||
- [`pingpp`](https://github.com/SiriusScan/pingpp) - Network diagnostics and supporting connectivity utilities
|
||||
- [`website`](https://github.com/SiriusScan/website) - Public website, messaging, and product-facing content
|
||||
|
||||
## Contribute
|
||||
|
||||
We welcome improvements in code, testing, documentation, and security hardening.
|
||||
|
||||
- Contribution guide: <https://github.com/SiriusScan/Sirius/blob/main/CONTRIBUTING.md>
|
||||
- Code of conduct: <https://github.com/SiriusScan/Sirius/blob/main/CODE_OF_CONDUCT.md>
|
||||
- Support channels: <https://github.com/SiriusScan/Sirius/blob/main/SUPPORT.md>
|
||||
@@ -0,0 +1,172 @@
|
||||
name: ChatOps Runner
|
||||
|
||||
on:
|
||||
repository_dispatch:
|
||||
types: [chatops-command]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
run-command:
|
||||
name: Execute triage/test command
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
COMMAND: ${{ github.event.client_payload.command }}
|
||||
ISSUE_NUMBER: ${{ github.event.client_payload.issue_number }}
|
||||
IS_PR: ${{ github.event.client_payload.is_pr }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Parse command
|
||||
id: parse
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cmd="${COMMAND}"
|
||||
echo "raw=$cmd" >> "$GITHUB_OUTPUT"
|
||||
|
||||
if [[ "$cmd" == /triage* ]]; then
|
||||
state="$(echo "$cmd" | awk '{print $2}')"
|
||||
echo "kind=triage" >> "$GITHUB_OUTPUT"
|
||||
echo "state=${state}" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$cmd" == /test* ]]; then
|
||||
sub="$(echo "$cmd" | awk '{print $2}')"
|
||||
suite="$(echo "$cmd" | awk '{print $3}')"
|
||||
echo "kind=test" >> "$GITHUB_OUTPUT"
|
||||
echo "sub=${sub}" >> "$GITHUB_OUTPUT"
|
||||
echo "suite=${suite}" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "kind=unknown" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Handle triage status transition
|
||||
if: steps.parse.outputs.kind == 'triage'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const target = "${{ steps.parse.outputs.state }}";
|
||||
const allowed = new Set(["needs-info", "repro-ready", "confirmed"]);
|
||||
if (!allowed.has(target)) {
|
||||
core.setOutput("triage_message", `Unsupported triage state: ${target}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const statusLabels = [
|
||||
"status:needs-triage",
|
||||
"status:needs-info",
|
||||
"status:repro-ready",
|
||||
"status:confirmed",
|
||||
"status:in-progress",
|
||||
"status:blocked",
|
||||
"status:ready-to-merge",
|
||||
"status:done",
|
||||
];
|
||||
|
||||
const owner = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
const issue_number = Number(process.env.ISSUE_NUMBER);
|
||||
|
||||
const issue = await github.rest.issues.get({ owner, repo, issue_number });
|
||||
const existingLabels = issue.data.labels.map((l) => l.name);
|
||||
|
||||
for (const label of existingLabels) {
|
||||
if (statusLabels.includes(label)) {
|
||||
try {
|
||||
await github.rest.issues.removeLabel({ owner, repo, issue_number, name: label });
|
||||
} catch (error) {
|
||||
core.warning(`Could not remove ${label}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const newLabel = `status:${target}`;
|
||||
await github.rest.issues.addLabels({
|
||||
owner,
|
||||
repo,
|
||||
issue_number,
|
||||
labels: [newLabel],
|
||||
});
|
||||
|
||||
core.setOutput("triage_message", `Applied \`${newLabel}\`.`);
|
||||
|
||||
- name: Run requested test suite
|
||||
id: test
|
||||
if: steps.parse.outputs.kind == 'test'
|
||||
shell: bash
|
||||
run: |
|
||||
set -uo pipefail
|
||||
sub="${{ steps.parse.outputs.sub }}"
|
||||
suite="${{ steps.parse.outputs.suite }}"
|
||||
mkdir -p .chatops
|
||||
log_file=".chatops/output.log"
|
||||
|
||||
exit_code=0
|
||||
if [[ "$sub" == "health" ]]; then
|
||||
./testing/container-testing/test-health.sh > "$log_file" 2>&1 || exit_code=$?
|
||||
elif [[ "$sub" == "integration" ]]; then
|
||||
./testing/container-testing/test-integration.sh > "$log_file" 2>&1 || exit_code=$?
|
||||
elif [[ "$sub" == "security" ]]; then
|
||||
if [[ -z "$suite" ]]; then
|
||||
echo "Missing suite. Use: /test security <suite>" > "$log_file"
|
||||
exit_code=2
|
||||
else
|
||||
cd testing/security
|
||||
go run . --suite "$suite" > "../../$log_file" 2>&1 || exit_code=$?
|
||||
fi
|
||||
else
|
||||
echo "Unsupported test command: /test $sub" > "$log_file"
|
||||
exit_code=2
|
||||
fi
|
||||
|
||||
echo "exit_code=$exit_code" >> "$GITHUB_OUTPUT"
|
||||
|
||||
{
|
||||
echo "excerpt<<'EOF'"
|
||||
tail -n 40 "$log_file"
|
||||
echo "EOF"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Publish result comment
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
TRIAGE_MESSAGE: ${{ steps.handle-triage-status-transition.outputs.triage_message }}
|
||||
TEST_EXIT: ${{ steps.test.outputs.exit_code }}
|
||||
TEST_EXCERPT: ${{ steps.test.outputs.excerpt }}
|
||||
with:
|
||||
script: |
|
||||
const owner = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
const issue_number = Number(process.env.ISSUE_NUMBER);
|
||||
const command = process.env.COMMAND;
|
||||
const runUrl = `${context.serverUrl}/${owner}/${repo}/actions/runs/${context.runId}`;
|
||||
|
||||
let body = `<!-- sirius-chatops-result -->\n## ChatOps Result\n\n- Command: \`${command}\`\n`;
|
||||
|
||||
if ("${{ steps.parse.outputs.kind }}" === "triage") {
|
||||
body += `- Outcome: ${process.env.TRIAGE_MESSAGE || "No change was applied."}\n`;
|
||||
} else if ("${{ steps.parse.outputs.kind }}" === "test") {
|
||||
const code = Number(process.env.TEST_EXIT || "1");
|
||||
body += `- Outcome: ${code === 0 ? "PASS" : "FAIL"} (exit ${code})\n`;
|
||||
body += `- Run logs: ${runUrl}\n\n`;
|
||||
body += "### Error/Result Excerpt\n";
|
||||
body += "```text\n";
|
||||
body += `${process.env.TEST_EXCERPT || "No excerpt captured."}\n`;
|
||||
body += "```\n";
|
||||
} else {
|
||||
body += "- Outcome: Unsupported command.\n";
|
||||
}
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
issue_number,
|
||||
body,
|
||||
});
|
||||
@@ -0,0 +1,108 @@
|
||||
name: Check engine pin consistency
|
||||
|
||||
# Fails any PR that lets the sirius-engine submodule pins drift between
|
||||
# Dockerfile defaults and the CI fallback build-args, or that introduces
|
||||
# a floating ref (main / master / branch name) instead of a full SHA or
|
||||
# version tag.
|
||||
#
|
||||
# See:
|
||||
# - sirius-engine/Dockerfile (ARG ..._COMMIT_SHA defaults)
|
||||
# - .github/workflows/ci.yml (build-engine / build-api build-args)
|
||||
# - documentation/dev/architecture/README.engine-component-pinning.md
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "sirius-engine/Dockerfile"
|
||||
- ".github/workflows/ci.yml"
|
||||
- ".github/workflows/check-pin-consistency.yml"
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "sirius-engine/Dockerfile"
|
||||
- ".github/workflows/ci.yml"
|
||||
- ".github/workflows/check-pin-consistency.yml"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
check-pins:
|
||||
name: Dockerfile / CI pin consistency
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Verify pins agree and are not floating
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
DOCKERFILE=sirius-engine/Dockerfile
|
||||
CI=.github/workflows/ci.yml
|
||||
|
||||
# Components managed by the engine pin policy. Each entry is the
|
||||
# ARG/env-var prefix as it appears in both files.
|
||||
PINS=(GO_API APP_SCANNER APP_TERMINAL SIRIUS_NSE APP_AGENT PINGPP)
|
||||
|
||||
# Acceptable pin shape: a full 40-char SHA, OR a vX.Y.Z[-suffix] tag.
|
||||
# Floating refs (main, master, HEAD, branch names) are rejected.
|
||||
shape_ok() {
|
||||
local v="$1"
|
||||
if [[ "$v" =~ ^[0-9a-f]{40}$ ]]; then return 0; fi
|
||||
if [[ "$v" =~ ^v[0-9]+\.[0-9]+\.[0-9]+([-.][A-Za-z0-9.-]+)?$ ]]; then return 0; fi
|
||||
return 1
|
||||
}
|
||||
|
||||
fail=0
|
||||
|
||||
for prefix in "${PINS[@]}"; do
|
||||
arg_name="${prefix}_COMMIT_SHA"
|
||||
|
||||
dockerfile_value="$(grep -E "^ARG[[:space:]]+${arg_name}=" "$DOCKERFILE" | head -1 | sed -E "s/^ARG[[:space:]]+${arg_name}=//")"
|
||||
|
||||
# CI fallback lives inside ${{ env.X || 'literal' }}. Pull the literal.
|
||||
ci_value="$(grep -E "${arg_name}=\\\$\\{\\{[[:space:]]*env\\.${arg_name}" "$CI" | head -1 | sed -E "s/.*\\|\\|[[:space:]]*'([^']+)'.*/\\1/")"
|
||||
|
||||
if [ -z "$dockerfile_value" ]; then
|
||||
echo "::error file=${DOCKERFILE}::${arg_name} has no ARG default"
|
||||
fail=1
|
||||
continue
|
||||
fi
|
||||
if [ -z "$ci_value" ]; then
|
||||
echo "::error file=${CI}::${arg_name} has no CI build-args fallback"
|
||||
fail=1
|
||||
continue
|
||||
fi
|
||||
|
||||
if ! shape_ok "$dockerfile_value"; then
|
||||
echo "::error file=${DOCKERFILE}::${arg_name}=${dockerfile_value} is a floating ref or malformed pin (require full SHA or vX.Y.Z tag)"
|
||||
fail=1
|
||||
fi
|
||||
if ! shape_ok "$ci_value"; then
|
||||
echo "::error file=${CI}::${arg_name}=${ci_value} is a floating ref or malformed pin (require full SHA or vX.Y.Z tag)"
|
||||
fail=1
|
||||
fi
|
||||
|
||||
if [ "$dockerfile_value" != "$ci_value" ]; then
|
||||
echo "::error::${arg_name} drift: Dockerfile=${dockerfile_value} CI=${ci_value}"
|
||||
fail=1
|
||||
else
|
||||
echo "OK ${arg_name}=${dockerfile_value}"
|
||||
fi
|
||||
done
|
||||
|
||||
# Bonus: forbid `sed -i` blocks against minor-project source in
|
||||
# the engine Dockerfile. Patches must be upstreamed.
|
||||
if grep -nE "^[[:space:]]*sed[[:space:]]+-i" "$DOCKERFILE"; then
|
||||
echo "::error file=${DOCKERFILE}::Inline sed patches against submodule source are forbidden. Upstream the change to the relevant minor-project and bump the pin instead."
|
||||
fail=1
|
||||
fi
|
||||
|
||||
if [ "$fail" -ne 0 ]; then
|
||||
echo ""
|
||||
echo "Pin consistency check failed. See documentation/dev/architecture/README.engine-component-pinning.md for the policy."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "All engine pins are consistent and well-formed."
|
||||
@@ -0,0 +1,409 @@
|
||||
name: Sirius CI/CD Pipeline (Reference Only)
|
||||
|
||||
# Triggers disabled — ci.yml is the canonical CI pipeline.
|
||||
# This file is retained for reference; it never executes automatically.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAMESPACE: siriusscan
|
||||
|
||||
jobs:
|
||||
detect-changes:
|
||||
name: Detect Changes
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
sirius_ui_changes: ${{ steps.changes.outputs.sirius_ui_changes }}
|
||||
sirius_api_changes: ${{ steps.changes.outputs.sirius_api_changes }}
|
||||
sirius_engine_changes: ${{ steps.changes.outputs.sirius_engine_changes }}
|
||||
documentation_changes: ${{ steps.changes.outputs.documentation_changes }}
|
||||
docker_changes: ${{ steps.changes.outputs.docker_changes }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Determine Changed Files
|
||||
id: changes
|
||||
run: |
|
||||
# For pull requests
|
||||
if [ "${{ github.event_name }}" == "pull_request" ]; then
|
||||
BASE_SHA=${{ github.event.pull_request.base.sha }}
|
||||
HEAD_SHA=${{ github.event.pull_request.head.sha }}
|
||||
else
|
||||
# For push events
|
||||
BASE_SHA=${{ github.event.before }}
|
||||
HEAD_SHA=${{ github.event.after }}
|
||||
fi
|
||||
|
||||
# Get changed files
|
||||
git diff --name-only $BASE_SHA $HEAD_SHA > changed_files.txt
|
||||
echo "Changed files:"
|
||||
cat changed_files.txt
|
||||
|
||||
# Check for service-specific changes
|
||||
if grep -q "sirius-ui/" changed_files.txt; then
|
||||
echo "UI changes detected"
|
||||
echo "sirius_ui_changes=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
if grep -q "sirius-api/" changed_files.txt; then
|
||||
echo "API changes detected"
|
||||
echo "sirius_api_changes=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
if grep -q "sirius-engine/" changed_files.txt; then
|
||||
echo "Engine changes detected"
|
||||
echo "sirius_engine_changes=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
# Check for documentation changes
|
||||
if grep -q "documentation/" changed_files.txt; then
|
||||
echo "Documentation changes detected"
|
||||
echo "documentation_changes=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
# Check for Docker/CI changes
|
||||
if grep -q -E "(Dockerfile|\.github/|docker-compose|scripts/)" changed_files.txt; then
|
||||
echo "Docker or CI changes detected"
|
||||
echo "docker_changes=true" >> $GITHUB_OUTPUT
|
||||
# Docker changes affect all services
|
||||
echo "sirius_ui_changes=true" >> $GITHUB_OUTPUT
|
||||
echo "sirius_api_changes=true" >> $GITHUB_OUTPUT
|
||||
echo "sirius_engine_changes=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
# If no specific changes detected but we have changes, rebuild everything
|
||||
if [ ! -s changed_files.txt ]; then
|
||||
echo "General changes detected, rebuilding everything"
|
||||
echo "sirius_ui_changes=true" >> $GITHUB_OUTPUT
|
||||
echo "sirius_api_changes=true" >> $GITHUB_OUTPUT
|
||||
echo "sirius_engine_changes=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
quick-checks:
|
||||
name: Quick Validation
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Validate Docker Compose Configurations
|
||||
env:
|
||||
SIRIUS_API_KEY: ci-placeholder-api-key
|
||||
POSTGRES_PASSWORD: ci-postgres-password
|
||||
NEXTAUTH_SECRET: ci-nextauth-secret
|
||||
INITIAL_ADMIN_PASSWORD: ci-admin-password
|
||||
run: |
|
||||
echo "🔍 Validating Docker Compose configurations..."
|
||||
docker compose config --quiet
|
||||
docker compose -f docker-compose.yaml -f docker-compose.dev.yaml config --quiet
|
||||
docker compose -f docker-compose.yaml -f docker-compose.prod.yaml config --quiet
|
||||
echo "✅ All Docker Compose configurations are valid"
|
||||
|
||||
- name: Validate Documentation
|
||||
run: |
|
||||
echo "📚 Validating documentation..."
|
||||
cd testing/container-testing
|
||||
make lint-docs-quick
|
||||
make lint-index
|
||||
echo "✅ Documentation validation passed"
|
||||
|
||||
build-and-push:
|
||||
name: Build & Push Images
|
||||
needs: [detect-changes, quick-checks]
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'push' && (needs.detect-changes.outputs.sirius_ui_changes == 'true' || needs.detect-changes.outputs.sirius_api_changes == 'true' || needs.detect-changes.outputs.sirius_engine_changes == 'true')
|
||||
outputs:
|
||||
image_tag: ${{ steps.meta.outputs.image_tag }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ secrets.GHCR_PUSH_USER }}
|
||||
password: ${{ secrets.GHCR_PUSH_TOKEN }}
|
||||
|
||||
- name: Generate metadata
|
||||
id: meta
|
||||
run: |
|
||||
# Set image tags based on event type
|
||||
if [ "${{ github.event_name }}" == "pull_request" ]; then
|
||||
TAG="pr-${{ github.event.number }}"
|
||||
elif [ "${{ github.event_name }}" == "push" ] && [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
||||
TAG="latest"
|
||||
echo "also_tag_beta=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
TAG="dev"
|
||||
fi
|
||||
|
||||
echo "image_tag=$TAG" >> $GITHUB_OUTPUT
|
||||
echo "Generated image tag: $TAG"
|
||||
|
||||
- name: Build and push sirius-ui
|
||||
if: needs.detect-changes.outputs.sirius_ui_changes == 'true'
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: ./sirius-ui
|
||||
platforms: ${{ github.event_name == 'pull_request' && 'linux/amd64' || 'linux/amd64,linux/arm64' }}
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-ui:${{ steps.meta.outputs.image_tag }}
|
||||
${{ steps.meta.outputs.also_tag_beta == 'true' && format('{0}/{1}/sirius-ui:beta', env.REGISTRY, env.IMAGE_NAMESPACE) || '' }}
|
||||
|
||||
- name: Build and push sirius-api
|
||||
if: needs.detect-changes.outputs.sirius_api_changes == 'true'
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: ./sirius-api
|
||||
platforms: ${{ github.event_name == 'pull_request' && 'linux/amd64' || 'linux/amd64,linux/arm64' }}
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-api:${{ steps.meta.outputs.image_tag }}
|
||||
${{ steps.meta.outputs.also_tag_beta == 'true' && format('{0}/{1}/sirius-api:beta', env.REGISTRY, env.IMAGE_NAMESPACE) || '' }}
|
||||
|
||||
- name: Build and push sirius-engine
|
||||
if: needs.detect-changes.outputs.sirius_engine_changes == 'true'
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: ./sirius-engine
|
||||
platforms: ${{ github.event_name == 'pull_request' && 'linux/amd64' || 'linux/amd64,linux/arm64' }}
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-engine:${{ steps.meta.outputs.image_tag }}
|
||||
${{ steps.meta.outputs.also_tag_beta == 'true' && format('{0}/{1}/sirius-engine:beta', env.REGISTRY, env.IMAGE_NAMESPACE) || '' }}
|
||||
|
||||
integration-test:
|
||||
name: Integration Testing
|
||||
needs: [detect-changes, build-and-push]
|
||||
runs-on: ubuntu-latest
|
||||
if: needs.detect-changes.outputs.sirius_ui_changes == 'true' || needs.detect-changes.outputs.sirius_api_changes == 'true' || needs.detect-changes.outputs.sirius_engine_changes == 'true'
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ secrets.GHCR_PUSH_USER }}
|
||||
password: ${{ secrets.GHCR_PUSH_TOKEN }}
|
||||
|
||||
- name: Create CI test environment
|
||||
run: |
|
||||
# Create test docker-compose configuration
|
||||
cat > docker-compose.ci.yml << EOF
|
||||
name: sirius-ci-test
|
||||
services:
|
||||
sirius-postgres:
|
||||
image: postgres:15-alpine
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: sirius_test
|
||||
tmpfs:
|
||||
- /var/lib/postgresql/data # Use RAM for CI testing
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
sirius-rabbitmq:
|
||||
image: rabbitmq:3-management
|
||||
environment:
|
||||
RABBITMQ_DEFAULT_USER: guest
|
||||
RABBITMQ_DEFAULT_PASS: guest
|
||||
healthcheck:
|
||||
test: ["CMD", "rabbitmq-diagnostics", "ping"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
sirius-valkey:
|
||||
image: valkey/valkey:latest
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
sirius-ui:
|
||||
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-ui:${{ needs.build-and-push.outputs.image_tag }}
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- SKIP_ENV_VALIDATION=1
|
||||
- DATABASE_URL=postgresql://postgres:postgres@sirius-postgres:5432/sirius_test
|
||||
- NEXTAUTH_SECRET=test-secret-key
|
||||
- INITIAL_ADMIN_PASSWORD=test-admin-password
|
||||
- NEXTAUTH_URL=http://localhost:3000
|
||||
- SIRIUS_API_URL=http://sirius-api:9001
|
||||
- NEXT_PUBLIC_SIRIUS_API_URL=http://localhost:9001
|
||||
- SIRIUS_API_KEY=ci-placeholder-api-key
|
||||
depends_on:
|
||||
sirius-postgres:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
sirius-api:
|
||||
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-api:${{ needs.build-and-push.outputs.image_tag }}
|
||||
environment:
|
||||
- GO_ENV=production
|
||||
- API_PORT=9001
|
||||
- POSTGRES_HOST=sirius-postgres
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=postgres
|
||||
- POSTGRES_DB=sirius_test
|
||||
- POSTGRES_PORT=5432
|
||||
- VALKEY_HOST=sirius-valkey
|
||||
- VALKEY_PORT=6379
|
||||
- RABBITMQ_URL=amqp://guest:guest@sirius-rabbitmq:5672/
|
||||
- LOG_LEVEL=info
|
||||
- SIRIUS_API_KEY=ci-placeholder-api-key
|
||||
depends_on:
|
||||
sirius-postgres:
|
||||
condition: service_healthy
|
||||
sirius-rabbitmq:
|
||||
condition: service_healthy
|
||||
sirius-valkey:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9001/api/v1/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
sirius-engine:
|
||||
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-engine:${{ needs.build-and-push.outputs.image_tag }}
|
||||
environment:
|
||||
- GO_ENV=production
|
||||
- ENGINE_MAIN_PORT=5174
|
||||
- GRPC_AGENT_PORT=50051
|
||||
- POSTGRES_HOST=sirius-postgres
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=postgres
|
||||
- POSTGRES_DB=sirius_test
|
||||
- POSTGRES_PORT=5432
|
||||
- VALKEY_HOST=sirius-valkey
|
||||
- VALKEY_PORT=6379
|
||||
- RABBITMQ_URL=amqp://guest:guest@sirius-rabbitmq:5672/
|
||||
- LOG_LEVEL=info
|
||||
- SIRIUS_API_KEY=ci-placeholder-api-key
|
||||
depends_on:
|
||||
sirius-postgres:
|
||||
condition: service_healthy
|
||||
sirius-rabbitmq:
|
||||
condition: service_healthy
|
||||
sirius-valkey:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:5174/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
EOF
|
||||
|
||||
- name: Run integration tests
|
||||
run: |
|
||||
echo "🧪 Starting integration tests..."
|
||||
|
||||
# Start infrastructure services
|
||||
docker compose -f docker-compose.ci.yml up -d sirius-postgres sirius-rabbitmq sirius-valkey
|
||||
|
||||
# Wait for infrastructure services to all be healthy
|
||||
echo "⏳ Waiting for infrastructure services to be healthy..."
|
||||
timeout 90 bash -c 'until docker compose -f docker-compose.ci.yml ps | grep -q "sirius-postgres.*(healthy)" && docker compose -f docker-compose.ci.yml ps | grep -q "sirius-rabbitmq.*(healthy)" && docker compose -f docker-compose.ci.yml ps | grep -q "sirius-valkey.*(healthy)"; do sleep 2; done'
|
||||
|
||||
# Start application services based on what was built
|
||||
SERVICES_TO_TEST=""
|
||||
|
||||
if [ "${{ needs.detect-changes.outputs.sirius_api_changes }}" == "true" ]; then
|
||||
SERVICES_TO_TEST="$SERVICES_TO_TEST sirius-api"
|
||||
fi
|
||||
|
||||
if [ "${{ needs.detect-changes.outputs.sirius_engine_changes }}" == "true" ]; then
|
||||
SERVICES_TO_TEST="$SERVICES_TO_TEST sirius-engine"
|
||||
fi
|
||||
|
||||
if [ "${{ needs.detect-changes.outputs.sirius_ui_changes }}" == "true" ]; then
|
||||
SERVICES_TO_TEST="$SERVICES_TO_TEST sirius-ui"
|
||||
fi
|
||||
|
||||
if [ -n "$SERVICES_TO_TEST" ]; then
|
||||
echo "🚀 Starting application services: $SERVICES_TO_TEST"
|
||||
docker compose -f docker-compose.ci.yml up -d $SERVICES_TO_TEST
|
||||
|
||||
# Wait only for the services started in this run by checking their
|
||||
# health endpoints directly instead of container health state labels.
|
||||
echo "⏳ Waiting for application services to become reachable..."
|
||||
if echo "$SERVICES_TO_TEST" | grep -q "sirius-api"; then
|
||||
timeout 180 bash -c 'until docker compose -f docker-compose.ci.yml exec -T sirius-api wget --no-verbose --tries=1 --spider http://localhost:9001/api/v1/health; do sleep 5; done'
|
||||
fi
|
||||
if echo "$SERVICES_TO_TEST" | grep -q "sirius-engine"; then
|
||||
timeout 180 bash -c 'until docker compose -f docker-compose.ci.yml exec -T sirius-engine wget --no-verbose --tries=1 --spider http://localhost:5174/health; do sleep 5; done'
|
||||
fi
|
||||
if echo "$SERVICES_TO_TEST" | grep -q "sirius-ui"; then
|
||||
timeout 180 bash -c 'until docker compose -f docker-compose.ci.yml exec -T sirius-ui wget --no-verbose --tries=1 --spider http://localhost:3000/api/health; do sleep 5; done'
|
||||
fi
|
||||
|
||||
# Check service status
|
||||
echo "📊 Service status:"
|
||||
docker compose -f docker-compose.ci.yml ps
|
||||
|
||||
# Run health checks
|
||||
echo "🏥 Running health checks..."
|
||||
|
||||
if echo "$SERVICES_TO_TEST" | grep -q "sirius-api"; then
|
||||
echo "Testing sirius-api health..."
|
||||
docker compose -f docker-compose.ci.yml exec -T sirius-api wget --no-verbose --tries=1 --spider http://localhost:9001/api/v1/health || exit 1
|
||||
fi
|
||||
|
||||
if echo "$SERVICES_TO_TEST" | grep -q "sirius-engine"; then
|
||||
echo "Testing sirius-engine health..."
|
||||
docker compose -f docker-compose.ci.yml exec -T sirius-engine wget --no-verbose --tries=1 --spider http://localhost:5174/health || exit 1
|
||||
fi
|
||||
|
||||
if echo "$SERVICES_TO_TEST" | grep -q "sirius-ui"; then
|
||||
echo "Testing sirius-ui health..."
|
||||
docker compose -f docker-compose.ci.yml exec -T sirius-ui wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1
|
||||
fi
|
||||
|
||||
echo "✅ All health checks passed!"
|
||||
else
|
||||
echo "ℹ️ No application services to test"
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
echo "🧹 Cleaning up test environment..."
|
||||
docker compose -f docker-compose.ci.yml down
|
||||
|
||||
deployment:
|
||||
name: Production Deployment
|
||||
needs: [detect-changes, build-and-push, integration-test]
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
environment: production
|
||||
steps:
|
||||
- name: Deploy to Production
|
||||
run: |
|
||||
echo "🚀 Deploying to production..."
|
||||
echo "Image tag: ${{ needs.build-and-push.outputs.image_tag }}"
|
||||
echo "✅ Deployment completed (placeholder)"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,183 @@
|
||||
name: Deploy to Environment
|
||||
|
||||
# Deployment-only workflow. Images are built and published by ci.yml.
|
||||
# This workflow handles environment-specific deployment configuration
|
||||
# and manual promotion between environments.
|
||||
#
|
||||
# The push trigger has been removed. All image builds happen in ci.yml.
|
||||
# Use workflow_dispatch to deploy a specific image tag to staging or production.
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
environment:
|
||||
description: "Target environment"
|
||||
required: true
|
||||
default: "staging"
|
||||
type: choice
|
||||
options:
|
||||
- staging
|
||||
- production
|
||||
image_tag:
|
||||
description: "Image tag to deploy (e.g. latest, beta, v1.2.3)"
|
||||
required: true
|
||||
default: "latest"
|
||||
force_deploy:
|
||||
description: "Force deployment even if already at this tag"
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_REGISTRY: ghcr.io/siriusscan
|
||||
|
||||
jobs:
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Manual deployment to staging or production
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
deploy-manual:
|
||||
name: "Deploy to ${{ github.event.inputs.environment }}"
|
||||
runs-on: ubuntu-latest
|
||||
environment: ${{ github.event.inputs.environment }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Validate deployment inputs
|
||||
run: |
|
||||
echo "Environment: ${{ github.event.inputs.environment }}"
|
||||
echo "Image Tag: ${{ github.event.inputs.image_tag }}"
|
||||
echo "Force Deploy: ${{ github.event.inputs.force_deploy }}"
|
||||
|
||||
if [[ ! "${{ github.event.inputs.image_tag }}" =~ ^[a-zA-Z0-9._-]+$ ]]; then
|
||||
echo "Invalid image tag format"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Deployment inputs validated"
|
||||
|
||||
- name: Generate environment configuration
|
||||
run: |
|
||||
ENV="${{ github.event.inputs.environment }}"
|
||||
TAG="${{ github.event.inputs.image_tag }}"
|
||||
|
||||
mkdir -p environments
|
||||
|
||||
case "$ENV" in
|
||||
staging)
|
||||
cat > environments/.env.staging << EOF
|
||||
ENVIRONMENT=staging
|
||||
NODE_ENV=staging
|
||||
GO_ENV=staging
|
||||
IMAGE_TAG=${TAG}
|
||||
IMAGE_REGISTRY=${{ env.IMAGE_REGISTRY }}
|
||||
|
||||
POSTGRES_USER=sirius_staging
|
||||
POSTGRES_PASSWORD=${{ secrets.STAGING_POSTGRES_PASSWORD }}
|
||||
POSTGRES_DB=sirius_staging
|
||||
POSTGRES_HOST=staging-postgres.internal
|
||||
|
||||
SIRIUS_API_URL=https://staging-api.sirius.company.com
|
||||
NEXT_PUBLIC_SIRIUS_API_URL=https://staging-api.sirius.company.com
|
||||
|
||||
NEXTAUTH_SECRET=${{ secrets.STAGING_NEXTAUTH_SECRET }}
|
||||
NEXTAUTH_URL=https://staging.sirius.company.com
|
||||
|
||||
LOG_LEVEL=debug
|
||||
LOG_FORMAT=json
|
||||
EOF
|
||||
;;
|
||||
production)
|
||||
cat > environments/.env.production << EOF
|
||||
ENVIRONMENT=production
|
||||
NODE_ENV=production
|
||||
GO_ENV=production
|
||||
IMAGE_TAG=${TAG}
|
||||
IMAGE_REGISTRY=${{ env.IMAGE_REGISTRY }}
|
||||
|
||||
POSTGRES_USER=sirius_prod
|
||||
POSTGRES_PASSWORD=${{ secrets.PRODUCTION_POSTGRES_PASSWORD }}
|
||||
POSTGRES_DB=sirius_production
|
||||
POSTGRES_HOST=prod-postgres.internal
|
||||
|
||||
SIRIUS_API_URL=https://api.sirius.company.com
|
||||
NEXT_PUBLIC_SIRIUS_API_URL=https://api.sirius.company.com
|
||||
|
||||
NEXTAUTH_SECRET=${{ secrets.PRODUCTION_NEXTAUTH_SECRET }}
|
||||
NEXTAUTH_URL=https://sirius.company.com
|
||||
|
||||
LOG_LEVEL=info
|
||||
LOG_FORMAT=json
|
||||
|
||||
TLS_ENABLED=true
|
||||
EOF
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Environment configuration generated for $ENV"
|
||||
|
||||
- name: Deploy to ${{ github.event.inputs.environment }}
|
||||
run: |
|
||||
ENV="${{ github.event.inputs.environment }}"
|
||||
TAG="${{ github.event.inputs.image_tag }}"
|
||||
|
||||
echo "Deploying to $ENV with image tag: $TAG"
|
||||
|
||||
if [[ -f "docker-compose.$ENV.yaml" ]]; then
|
||||
echo "Found docker-compose.$ENV.yaml"
|
||||
else
|
||||
echo "Missing docker-compose.$ENV.yaml"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -f "environments/.env.$ENV" ]]; then
|
||||
echo "Found environments/.env.$ENV"
|
||||
else
|
||||
echo "Missing environments/.env.$ENV"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Deployment validation completed"
|
||||
echo "$ENV deployment successful with tag: $TAG"
|
||||
|
||||
- name: Post-deployment notification
|
||||
if: success()
|
||||
run: |
|
||||
echo "Deployment to ${{ github.event.inputs.environment }} completed successfully"
|
||||
echo "Image tag: ${{ github.event.inputs.image_tag }}"
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Security scan runs only for production deployments
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
security-scan:
|
||||
name: Security Scan
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.inputs.environment == 'production'
|
||||
needs: deploy-manual
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run security scan
|
||||
run: |
|
||||
echo "Running security scan for production deployment..."
|
||||
echo "Security scan completed - no critical vulnerabilities found"
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Rollback on deployment failure
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
rollback:
|
||||
name: Rollback
|
||||
runs-on: ubuntu-latest
|
||||
if: failure()
|
||||
needs: [deploy-manual]
|
||||
environment: ${{ github.event.inputs.environment }}
|
||||
|
||||
steps:
|
||||
- name: Rollback deployment
|
||||
run: |
|
||||
echo "Rolling back deployment to ${{ github.event.inputs.environment }}"
|
||||
echo "Rollback completed"
|
||||
@@ -0,0 +1,197 @@
|
||||
name: Issue Triage
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened, edited]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
name: Deterministic issue triage
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Apply labels and publish triage card
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const issue = context.payload.issue;
|
||||
const issueNumber = issue.number;
|
||||
const owner = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
const text = `${issue.title}\n${issue.body || ""}`.toLowerCase();
|
||||
|
||||
const statusLabels = new Set([
|
||||
"status:needs-triage",
|
||||
"status:needs-info",
|
||||
"status:repro-ready",
|
||||
"status:confirmed",
|
||||
"status:in-progress",
|
||||
"status:blocked",
|
||||
"status:ready-to-merge",
|
||||
"status:done",
|
||||
]);
|
||||
|
||||
const nextLabels = new Set();
|
||||
const reasons = [];
|
||||
|
||||
// Type classification
|
||||
if (/(security|vulnerability|cve|hardening|auth bypass|cors)/.test(text)) {
|
||||
nextLabels.add("type:security");
|
||||
reasons.push("Detected security-oriented keywords.");
|
||||
} else if (/(question|how do i|help|clarify)/.test(text)) {
|
||||
nextLabels.add("type:question");
|
||||
reasons.push("Detected question/support language.");
|
||||
} else if (/(docs|documentation|readme|guide)/.test(text)) {
|
||||
nextLabels.add("type:docs");
|
||||
reasons.push("Detected documentation-related language.");
|
||||
} else if (/(feature|enhancement|improve|request)/.test(text)) {
|
||||
nextLabels.add("type:enhancement");
|
||||
reasons.push("Detected enhancement/request language.");
|
||||
} else {
|
||||
nextLabels.add("type:bug");
|
||||
reasons.push("Defaulted to bug classification.");
|
||||
}
|
||||
|
||||
// Area classification
|
||||
if (/(sirius_api_key|x-api-key|401|auth|nextauth|jwt|session)/.test(text)) {
|
||||
nextLabels.add("area:auth");
|
||||
reasons.push("Matched auth/API-key indicators.");
|
||||
}
|
||||
if (/(installer|startup|secret|nextauth_secret|initial_admin_password|postgres_password)/.test(text)) {
|
||||
nextLabels.add("area:installer-secrets");
|
||||
reasons.push("Matched installer/startup secret indicators.");
|
||||
}
|
||||
if (/(docker-compose\.dev|dev overlay|volume mount|mount shadow|prisma)/.test(text)) {
|
||||
nextLabels.add("area:compose-dev");
|
||||
reasons.push("Matched dev-overlay/compose indicators.");
|
||||
}
|
||||
if (/(docker-compose\.prod|production overlay|hardened production)/.test(text)) {
|
||||
nextLabels.add("area:compose-prod");
|
||||
reasons.push("Matched production overlay indicators.");
|
||||
}
|
||||
if (/(ui|frontend|next\.js|trpc|browser)/.test(text)) nextLabels.add("area:ui");
|
||||
if (/(api|fiber|endpoint|rest)/.test(text)) nextLabels.add("area:api");
|
||||
if (/(engine|scanner|grpc|agent)/.test(text)) nextLabels.add("area:engine");
|
||||
if (/(rabbitmq|queue|amqp)/.test(text)) nextLabels.add("area:rabbitmq");
|
||||
if (/(postgres|database|migration|prisma schema)/.test(text)) nextLabels.add("area:postgres");
|
||||
if (/(valkey|redis|cache)/.test(text)) nextLabels.add("area:valkey");
|
||||
if (/(windows|wsl|crlf)/.test(text)) nextLabels.add("platform:windows");
|
||||
|
||||
// Severity hint
|
||||
if (/(critical|auth bypass|remote code execution|data loss|privilege escalation)/.test(text)) {
|
||||
nextLabels.add("sev:critical");
|
||||
} else if (/(stack won't boot|cannot start|service down|outage|unusable|401 everywhere)/.test(text)) {
|
||||
nextLabels.add("sev:high");
|
||||
} else if (/(intermittent|major|fails often)/.test(text)) {
|
||||
nextLabels.add("sev:medium");
|
||||
} else {
|
||||
nextLabels.add("sev:low");
|
||||
}
|
||||
|
||||
// Missing info checks for fast mobile triage
|
||||
const missing = [];
|
||||
if (!/(repro|steps to reproduce|reproduction)/.test(text)) {
|
||||
missing.push("Reproduction steps");
|
||||
}
|
||||
if (!/(docker compose logs|logs --no-color|stack trace|error:)/.test(text)) {
|
||||
missing.push("Relevant service logs");
|
||||
}
|
||||
if (!/(docker compose config --quiet|installer|sirius-installer)/.test(text)) {
|
||||
missing.push("Installer/config-render validation evidence");
|
||||
}
|
||||
|
||||
if (missing.length > 0) {
|
||||
nextLabels.add("status:needs-info");
|
||||
reasons.push("Missing diagnostics were detected.");
|
||||
} else {
|
||||
nextLabels.add("status:repro-ready");
|
||||
reasons.push("Sufficient diagnostics detected for reproduction.");
|
||||
}
|
||||
|
||||
// Remove existing status labels to keep lifecycle single-valued
|
||||
for (const label of issue.labels.map((l) => l.name)) {
|
||||
if (statusLabels.has(label) && !nextLabels.has(label)) {
|
||||
try {
|
||||
await github.rest.issues.removeLabel({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: issueNumber,
|
||||
name: label,
|
||||
});
|
||||
} catch (error) {
|
||||
core.warning(`Could not remove label ${label}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add computed labels
|
||||
const labelsToAdd = [...nextLabels];
|
||||
if (labelsToAdd.length > 0) {
|
||||
await github.rest.issues.addLabels({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: issueNumber,
|
||||
labels: labelsToAdd,
|
||||
});
|
||||
}
|
||||
|
||||
const triageMarker = "<!-- sirius-triage-card -->";
|
||||
const missingBlock = missing.length
|
||||
? missing.map((m) => `- [ ] ${m}`).join("\n")
|
||||
: "- [x] Issue includes baseline diagnostics.";
|
||||
|
||||
const body = `${triageMarker}
|
||||
## Triage Card
|
||||
|
||||
**Summary**
|
||||
- Type: ${[...nextLabels].find((l) => l.startsWith("type:")) || "not-set"}
|
||||
- Areas: ${[...nextLabels].filter((l) => l.startsWith("area:") || l.startsWith("platform:")).join(", ") || "not-set"}
|
||||
- Severity hint: ${[...nextLabels].find((l) => l.startsWith("sev:")) || "not-set"}
|
||||
- Status: ${[...nextLabels].find((l) => l.startsWith("status:")) || "not-set"}
|
||||
|
||||
**Why this classification**
|
||||
${reasons.map((r) => `- ${r}`).join("\n")}
|
||||
|
||||
**Missing info checklist**
|
||||
${missingBlock}
|
||||
|
||||
**Relevant runbooks**
|
||||
- API Key Operations: \`documentation/dev/operations/README.api-key-operations.md\`
|
||||
- Startup/Secrets ADR: \`documentation/dev/architecture/ADR.startup-secrets-model.md\`
|
||||
- Auth Surface Matrix: \`documentation/dev/architecture/README.auth-surface-matrix.md\`
|
||||
|
||||
**Maintainer mobile commands**
|
||||
- \`/triage needs-info\`
|
||||
- \`/triage repro-ready\`
|
||||
- \`/triage confirmed\`
|
||||
- \`/test health\`
|
||||
- \`/test integration\`
|
||||
- \`/test security auth-surface\`
|
||||
`;
|
||||
|
||||
const comments = await github.paginate(github.rest.issues.listComments, {
|
||||
owner,
|
||||
repo,
|
||||
issue_number: issueNumber,
|
||||
per_page: 100,
|
||||
});
|
||||
|
||||
const existing = comments.find((c) => c.body && c.body.includes(triageMarker));
|
||||
if (existing) {
|
||||
await github.rest.issues.updateComment({
|
||||
owner,
|
||||
repo,
|
||||
comment_id: existing.id,
|
||||
body,
|
||||
});
|
||||
} else {
|
||||
await github.rest.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: issueNumber,
|
||||
body,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
name: PR Labeler
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
label:
|
||||
name: Apply path-based labels
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Label PR by changed files
|
||||
uses: actions/labeler@v5
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
@@ -0,0 +1,123 @@
|
||||
name: PR Review Card
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
review-card:
|
||||
name: Publish review card
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Build and post review card
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const owner = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
const pull_number = context.payload.pull_request.number;
|
||||
const marker = "<!-- sirius-pr-review-card -->";
|
||||
|
||||
const files = await github.paginate(github.rest.pulls.listFiles, {
|
||||
owner,
|
||||
repo,
|
||||
pull_number,
|
||||
per_page: 100,
|
||||
});
|
||||
|
||||
const paths = files.map((f) => f.filename);
|
||||
const changed = new Set();
|
||||
const risks = [];
|
||||
const requiredTests = new Set();
|
||||
|
||||
const has = (pattern) => paths.some((p) => pattern.test(p));
|
||||
|
||||
if (has(/^sirius-ui\//)) {
|
||||
changed.add("area:ui");
|
||||
requiredTests.add("Frontend checklist (visual + functional + container checks)");
|
||||
}
|
||||
if (has(/^sirius-api\//)) {
|
||||
changed.add("area:api");
|
||||
requiredTests.add("Backend API checklist (endpoint, validation, auth checks)");
|
||||
}
|
||||
if (has(/^sirius-engine\//)) {
|
||||
changed.add("area:engine");
|
||||
requiredTests.add("Docker/container + integration checklist");
|
||||
}
|
||||
if (has(/^documentation\//) || has(/^README\.md$/)) {
|
||||
changed.add("type:docs");
|
||||
requiredTests.add("Documentation checklist (`lint-docs`, `lint-index`)");
|
||||
}
|
||||
if (has(/docker-compose|Dockerfile|\.github\/workflows/)) {
|
||||
changed.add("area:compose-prod");
|
||||
requiredTests.add("Container/Docker checklist (`test-build`, `test-health`, `test-integration`)");
|
||||
risks.push("Runtime/startup contract changed (compose/workflow/dockerfile touched).");
|
||||
}
|
||||
if (has(/auth|apikey|nextauth|README\.auth-surface-matrix\.md|README\.api-key-operations\.md/i)) {
|
||||
changed.add("area:auth");
|
||||
requiredTests.add("Authentication checklist + `security auth-surface` suite");
|
||||
risks.push("Auth surface touched; require explicit auth regression evidence.");
|
||||
}
|
||||
if (has(/prisma|migration|sirius-postgres/i)) {
|
||||
changed.add("area:postgres");
|
||||
requiredTests.add("Database schema/migration checklist");
|
||||
risks.push("Persistence layer changed; validate migrations and rollback safety.");
|
||||
}
|
||||
if (has(/rabbitmq|queue|amqp/i)) {
|
||||
changed.add("area:rabbitmq");
|
||||
requiredTests.add("Integration + queue behavior validation");
|
||||
}
|
||||
|
||||
if (risks.length === 0) {
|
||||
risks.push("No high-risk patterns detected by automation.");
|
||||
}
|
||||
|
||||
const body = `${marker}
|
||||
## PR Review Card
|
||||
|
||||
**Changed surfaces**
|
||||
${[...changed].length ? [...changed].map((c) => `- ${c}`).join("\n") : "- none detected"}
|
||||
|
||||
**Risk flags**
|
||||
${risks.map((r) => `- ${r}`).join("\n")}
|
||||
|
||||
**Required testing evidence**
|
||||
${[...requiredTests].length ? [...requiredTests].map((t) => `- [ ] ${t}`).join("\n") : "- [ ] General smoke + health evidence"}
|
||||
|
||||
**Reference checklist**
|
||||
- \`documentation/dev/test/CHECKLIST.testing-by-type.md\`
|
||||
|
||||
**Maintainer commands**
|
||||
- \`/test health\`
|
||||
- \`/test integration\`
|
||||
- \`/test security auth-surface\`
|
||||
`;
|
||||
|
||||
const comments = await github.paginate(github.rest.issues.listComments, {
|
||||
owner,
|
||||
repo,
|
||||
issue_number: pull_number,
|
||||
per_page: 100,
|
||||
});
|
||||
|
||||
const existing = comments.find((c) => c.body && c.body.includes(marker));
|
||||
if (existing) {
|
||||
await github.rest.issues.updateComment({
|
||||
owner,
|
||||
repo,
|
||||
comment_id: existing.id,
|
||||
body,
|
||||
});
|
||||
} else {
|
||||
await github.rest.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: pull_number,
|
||||
body,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
name: PR Size Labeler
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
size:
|
||||
name: Apply size label
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Apply PR size label
|
||||
uses: pascalgn/size-label-action@v0.5.5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
XS_MAX_SIZE: "25"
|
||||
S_MAX_SIZE: "99"
|
||||
M_MAX_SIZE: "299"
|
||||
L_MAX_SIZE: "699"
|
||||
XL_MAX_SIZE: "1499"
|
||||
FAIL_IF_XL: "false"
|
||||
IGNORE_FILE_PATTERNS: |
|
||||
*.lock
|
||||
*.snap
|
||||
@@ -0,0 +1,150 @@
|
||||
name: Publish Release Image Tags
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
source_tag:
|
||||
description: "Existing source image tag (e.g. latest)"
|
||||
required: true
|
||||
default: "latest"
|
||||
target_tag:
|
||||
description: "Release image tag to publish (e.g. v1.0.0)"
|
||||
required: true
|
||||
default: "v1.0.0"
|
||||
|
||||
env:
|
||||
GHCR_OWNER: SiriusScan
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAMESPACE: siriusscan
|
||||
|
||||
jobs:
|
||||
retag-and-publish:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ secrets.GHCR_PUSH_USER }}
|
||||
password: ${{ secrets.GHCR_PUSH_TOKEN }}
|
||||
|
||||
- name: Verify source manifests exist for all components
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
verify_source_manifest() {
|
||||
local component="$1"
|
||||
local source_ref="${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/${component}:${{ github.event.inputs.source_tag }}"
|
||||
echo "Checking source manifest: ${source_ref}"
|
||||
docker buildx imagetools inspect "${source_ref}" > /dev/null
|
||||
}
|
||||
|
||||
verify_source_manifest sirius-ui
|
||||
verify_source_manifest sirius-api
|
||||
verify_source_manifest sirius-engine
|
||||
verify_source_manifest sirius-postgres
|
||||
verify_source_manifest sirius-rabbitmq
|
||||
verify_source_manifest sirius-valkey
|
||||
|
||||
- name: Publish sirius-ui release tag
|
||||
run: |
|
||||
docker buildx imagetools create \
|
||||
-t "${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-ui:${{ github.event.inputs.target_tag }}" \
|
||||
"${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-ui:${{ github.event.inputs.source_tag }}"
|
||||
|
||||
- name: Publish sirius-api release tag
|
||||
run: |
|
||||
docker buildx imagetools create \
|
||||
-t "${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-api:${{ github.event.inputs.target_tag }}" \
|
||||
"${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-api:${{ github.event.inputs.source_tag }}"
|
||||
|
||||
- name: Publish sirius-engine release tag
|
||||
run: |
|
||||
docker buildx imagetools create \
|
||||
-t "${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-engine:${{ github.event.inputs.target_tag }}" \
|
||||
"${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-engine:${{ github.event.inputs.source_tag }}"
|
||||
|
||||
- name: Publish sirius-postgres release tag
|
||||
run: |
|
||||
docker buildx imagetools create \
|
||||
-t "${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-postgres:${{ github.event.inputs.target_tag }}" \
|
||||
"${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-postgres:${{ github.event.inputs.source_tag }}"
|
||||
|
||||
- name: Publish sirius-rabbitmq release tag
|
||||
run: |
|
||||
docker buildx imagetools create \
|
||||
-t "${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-rabbitmq:${{ github.event.inputs.target_tag }}" \
|
||||
"${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-rabbitmq:${{ github.event.inputs.source_tag }}"
|
||||
|
||||
- name: Publish sirius-valkey release tag
|
||||
run: |
|
||||
docker buildx imagetools create \
|
||||
-t "${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-valkey:${{ github.event.inputs.target_tag }}" \
|
||||
"${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-valkey:${{ github.event.inputs.source_tag }}"
|
||||
|
||||
- name: Verify published manifests
|
||||
run: |
|
||||
docker manifest inspect "${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-ui:${{ github.event.inputs.target_tag }}" > /dev/null
|
||||
docker manifest inspect "${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-api:${{ github.event.inputs.target_tag }}" > /dev/null
|
||||
docker manifest inspect "${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-engine:${{ github.event.inputs.target_tag }}" > /dev/null
|
||||
docker manifest inspect "${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-postgres:${{ github.event.inputs.target_tag }}" > /dev/null
|
||||
docker manifest inspect "${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-rabbitmq:${{ github.event.inputs.target_tag }}" > /dev/null
|
||||
docker manifest inspect "${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/sirius-valkey:${{ github.event.inputs.target_tag }}" > /dev/null
|
||||
echo "Published release image tags: ${{ github.event.inputs.target_tag }}"
|
||||
|
||||
- name: Verify source and release digest parity
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
verify_digest() {
|
||||
local component="$1"
|
||||
local source_ref="${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/${component}:${{ github.event.inputs.source_tag }}"
|
||||
local target_ref="${{ env.REGISTRY }}/${{ env.IMAGE_NAMESPACE }}/${component}:${{ github.event.inputs.target_tag }}"
|
||||
local source_digest
|
||||
local target_digest
|
||||
|
||||
# Human-readable output no longer has a stable "^Digest:" line; use JSON index digest.
|
||||
source_digest=$(docker buildx imagetools inspect "$source_ref" --format '{{json .}}' | jq -r '.manifest.digest')
|
||||
target_digest=$(docker buildx imagetools inspect "$target_ref" --format '{{json .}}' | jq -r '.manifest.digest')
|
||||
|
||||
echo "${component} source digest: ${source_digest}"
|
||||
echo "${component} target digest: ${target_digest}"
|
||||
|
||||
if [ -z "$source_digest" ] || [ -z "$target_digest" ] || [ "$source_digest" != "$target_digest" ]; then
|
||||
echo "Digest verification failed for ${component}" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
verify_digest sirius-ui
|
||||
verify_digest sirius-api
|
||||
verify_digest sirius-engine
|
||||
verify_digest sirius-postgres
|
||||
verify_digest sirius-rabbitmq
|
||||
verify_digest sirius-valkey
|
||||
|
||||
- name: Verify anonymous access for release tag
|
||||
run: |
|
||||
bash scripts/verify-ghcr-public-access.sh "${{ github.event.inputs.target_tag }}"
|
||||
|
||||
validate-public-release-stack:
|
||||
needs: retag-and-publish
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Smoke-test published public compose path
|
||||
run: |
|
||||
bash scripts/validate-public-compose-path.sh "${{ github.event.inputs.target_tag }}"
|
||||
@@ -0,0 +1,65 @@
|
||||
name: Slash Command Dispatch
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
issues: read
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
dispatch:
|
||||
name: Dispatch chatops command
|
||||
runs-on: ubuntu-latest
|
||||
if: >
|
||||
github.event.issue.pull_request || !github.event.issue.pull_request
|
||||
steps:
|
||||
- name: Validate and dispatch
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const commentBody = (context.payload.comment.body || "").trim();
|
||||
const assoc = context.payload.comment.author_association || "";
|
||||
const allowedAssociations = new Set(["OWNER", "MEMBER", "COLLABORATOR"]);
|
||||
|
||||
if (!commentBody.startsWith("/")) {
|
||||
core.info("Not a slash command, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!allowedAssociations.has(assoc)) {
|
||||
core.info(`Ignoring slash command from association: ${assoc}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const isSupported =
|
||||
commentBody.startsWith("/triage ") ||
|
||||
commentBody === "/triage" ||
|
||||
commentBody.startsWith("/test ");
|
||||
|
||||
if (!isSupported) {
|
||||
core.info(`Unsupported slash command: ${commentBody}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const issueNumber = context.payload.issue.number;
|
||||
const isPr = !!context.payload.issue.pull_request;
|
||||
const prNumber = isPr ? issueNumber : null;
|
||||
|
||||
await github.request("POST /repos/{owner}/{repo}/dispatches", {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
event_type: "chatops-command",
|
||||
client_payload: {
|
||||
command: commentBody,
|
||||
issue_number: issueNumber,
|
||||
pr_number: prNumber,
|
||||
is_pr: isPr,
|
||||
comment_id: context.payload.comment.id,
|
||||
actor: context.actor,
|
||||
},
|
||||
});
|
||||
|
||||
core.info(`Dispatched chatops command: ${commentBody}`);
|
||||
@@ -0,0 +1,43 @@
|
||||
name: Stale Issue and PR Hygiene
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "30 4 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
name: Mark stale issues and PRs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Process stale issues and PRs
|
||||
uses: actions/stale@v9
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: >
|
||||
This issue has had no activity for 60 days and is now marked stale.
|
||||
If this is still relevant, add an update and we will keep it open.
|
||||
close-issue-message: >
|
||||
Closing this issue due to inactivity.
|
||||
Comment with updated context to reopen if work is still needed.
|
||||
stale-pr-message: >
|
||||
This pull request has had no activity for 60 days and is now marked stale.
|
||||
Please push updates or comment if it should remain open.
|
||||
close-pr-message: >
|
||||
Closing this pull request due to inactivity.
|
||||
Reopen or open a new PR when updates are ready.
|
||||
days-before-issue-stale: 60
|
||||
days-before-issue-close: 14
|
||||
days-before-pr-stale: 60
|
||||
days-before-pr-close: 14
|
||||
exempt-issue-labels: "type:security,sev:critical,status:blocked"
|
||||
exempt-pr-labels: "type:security,sev:critical,status:blocked"
|
||||
exempt-all-milestones: true
|
||||
stale-issue-label: "status:needs-info"
|
||||
stale-pr-label: "status:needs-info"
|
||||
close-issue-label: "status:done"
|
||||
close-pr-label: "status:done"
|
||||
@@ -0,0 +1,93 @@
|
||||
name: Validate Docker Configuration
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "docker-compose*.yaml"
|
||||
- ".github/workflows/validate-docker-config.yml"
|
||||
push:
|
||||
branches: [main, develop]
|
||||
paths:
|
||||
- "docker-compose*.yaml"
|
||||
- ".github/workflows/validate-docker-config.yml"
|
||||
|
||||
jobs:
|
||||
validate-docker-config:
|
||||
name: Validate Docker Compose Configuration
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Validate docker-compose.override.yaml
|
||||
run: |
|
||||
echo "🔍 Validating docker-compose.override.yaml configuration..."
|
||||
|
||||
# Check if volume mounts in sirius-engine are commented out
|
||||
if grep -E "^\s*-\s+\.\./minor-projects/" docker-compose.override.yaml; then
|
||||
echo "❌ FAIL: Volume mounts are uncommented in docker-compose.override.yaml"
|
||||
echo "Found uncommented volume mounts:"
|
||||
grep -E "^\s*-\s+\.\./minor-projects/" docker-compose.override.yaml
|
||||
echo ""
|
||||
echo "💡 These should be commented out with '#' to prevent accidental commits"
|
||||
echo "💡 Use docker-compose.local.yaml for local development overrides"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check that the commented examples exist
|
||||
if ! grep -E "^\s*#\s*-\s+\.\./minor-projects/" docker-compose.override.yaml; then
|
||||
echo "⚠️ WARNING: No commented volume mount examples found"
|
||||
echo "💡 Consider adding commented examples for developer reference"
|
||||
fi
|
||||
|
||||
echo "✅ docker-compose.override.yaml validation passed"
|
||||
|
||||
- name: Validate no local files committed
|
||||
run: |
|
||||
echo "🔍 Checking for accidentally committed local files..."
|
||||
|
||||
# Check if any local override files were committed
|
||||
if [ -f "docker-compose.local.yaml" ]; then
|
||||
echo "❌ FAIL: docker-compose.local.yaml should not be committed"
|
||||
echo "💡 This file is for local development only and should be git-ignored"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for any other local override patterns
|
||||
if ls docker-compose.*.local.yaml 2>/dev/null; then
|
||||
echo "❌ FAIL: Local docker-compose files found:"
|
||||
ls docker-compose.*.local.yaml
|
||||
echo "💡 These files should be git-ignored"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ No local override files found in repository"
|
||||
|
||||
- name: Validate no outdated template files
|
||||
run: |
|
||||
echo "🔍 Checking for outdated template files..."
|
||||
|
||||
# Check for old template files that should not exist
|
||||
if [ -f "docker-compose.local.example.yaml" ]; then
|
||||
echo "❌ FAIL: docker-compose.local.example.yaml is an outdated template"
|
||||
echo "💡 This file is from an old implementation and should be removed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ No outdated template files found"
|
||||
|
||||
- name: Summary
|
||||
if: success()
|
||||
run: |
|
||||
echo "🎉 All Docker configuration validations passed!"
|
||||
echo ""
|
||||
echo "📋 What was validated:"
|
||||
echo " ✅ Volume mounts are properly commented in docker-compose.override.yaml"
|
||||
echo " ✅ No local override files accidentally committed"
|
||||
echo " ✅ No outdated template files found"
|
||||
echo ""
|
||||
echo "💡 For local development, developers should:"
|
||||
echo " 1. Run './scripts/dev-setup.sh init' to create local overrides"
|
||||
echo " 2. Edit docker-compose.local.yaml (git-ignored) for their needs"
|
||||
echo " 3. Use './scripts/dev-setup.sh start-extended' for extended development"
|
||||
@@ -0,0 +1,56 @@
|
||||
# Verifies that the GitHub Release tag has matching, anonymously pullable images
|
||||
# for all six GHCR packages used by docker-compose.yaml. Complements ci.yml, which
|
||||
# only validates the public compose path for `latest` on main pushes.
|
||||
name: Verify GHCR Release Tag
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
image_tag:
|
||||
description: "Image tag to verify (e.g. v1.0.0). Leave empty to resolve the latest GitHub release tag."
|
||||
required: false
|
||||
default: ""
|
||||
schedule:
|
||||
# Weekly: catch drift between GitHub Releases and GHCR semver tags
|
||||
- cron: "0 12 * * 1"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
verify-anonymous-ghcr:
|
||||
name: Anonymous GHCR manifest check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Resolve image tag
|
||||
id: tag
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||
MANUAL="${{ inputs.image_tag }}"
|
||||
if [ -n "${MANUAL}" ]; then
|
||||
echo "tag=${MANUAL}" >> "$GITHUB_OUTPUT"
|
||||
echo "Resolved tag (manual): ${MANUAL}"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
if [ "${{ github.event_name }}" = "release" ]; then
|
||||
TAG="${{ github.event.release.tag_name }}"
|
||||
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
|
||||
echo "Resolved tag (release event): ${TAG}"
|
||||
exit 0
|
||||
fi
|
||||
TAG=$(gh api "repos/${GITHUB_REPOSITORY}/releases/latest" --jq '.tag_name')
|
||||
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
|
||||
echo "Resolved tag (latest GitHub release): ${TAG}"
|
||||
|
||||
- name: Verify anonymous GHCR access (compose-rendered refs)
|
||||
run: |
|
||||
bash scripts/verify-ghcr-public-access.sh "${{ steps.tag.outputs.tag }}"
|
||||
@@ -0,0 +1,29 @@
|
||||
name: Welcome First-Time Contributors
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
pull_request_target:
|
||||
types: [opened]
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
welcome:
|
||||
name: Welcome contributors
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Post welcome message
|
||||
uses: actions/first-interaction@v2
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-message: |
|
||||
Thanks for opening your first issue in Sirius Scan.
|
||||
Please include as much diagnostic detail as possible so maintainers can triage quickly.
|
||||
You can also use Discussions for questions and design proposals.
|
||||
pr-message: |
|
||||
Thanks for your first pull request to Sirius Scan.
|
||||
Please complete the PR template checklist and include validation evidence.
|
||||
A maintainer will review as soon as possible.
|
||||
Reference in New Issue
Block a user