Compare commits

...

1008 Commits

Author SHA1 Message Date
GitHub Actions
3fe592926d chore: update electron-to-chromium version to 1.5.342 in package-lock.json 2026-04-22 00:23:17 +00:00
GitHub Actions
5bcf3069c6 chore: ensure both coverage output directories are created in frontend test coverage script 2026-04-22 00:21:53 +00:00
GitHub Actions
6546130518 chore: update QA report with detailed gate status and revalidation results 2026-04-22 00:13:35 +00:00
GitHub Actions
07108cfa8d chore: refactor frontend test coverage script to improve directory handling and cleanup 2026-04-22 00:13:35 +00:00
GitHub Actions
de945c358b chore: update coverage reports directory configuration in vitest 2026-04-22 00:13:35 +00:00
GitHub Actions
e5c7b85f82 chore: enhance accessibility tests by adding route readiness checks 2026-04-22 00:13:35 +00:00
GitHub Actions
6e06cc3396 chore: update security test paths in Playwright configuration 2026-04-22 00:13:35 +00:00
GitHub Actions
7e3b5b13b4 chore: update @tailwindcss packages to version 4.2.4 and tapable to version 2.3.3 2026-04-22 00:13:35 +00:00
GitHub Actions
91ba53476c chore: update QA/Security DoD Audit Report with latest findings and gate statuses 2026-04-22 00:13:35 +00:00
GitHub Actions
442425a4a5 chore: update version to v0.27.0 2026-04-22 00:13:35 +00:00
GitHub Actions
71fe278e33 chore: update Docker client initialization and container listing logic 2026-04-22 00:13:35 +00:00
GitHub Actions
468af25887 chore: add lefthook and backend test output files to .gitignore 2026-04-22 00:13:35 +00:00
GitHub Actions
d437de1ccf chore: add new output files to .gitignore for scan and coverage results 2026-04-22 00:13:35 +00:00
GitHub Actions
8c56f40131 chore: remove unused libc entries and clean up dependencies in package-lock.json 2026-04-22 00:13:35 +00:00
GitHub Actions
2bf4f869ab chore: update vulnerability suppression and documentation for CVE-2026-34040 in .grype.yaml, .trivyignore, and SECURITY.md 2026-04-22 00:13:35 +00:00
GitHub Actions
dd698afa7e chore: update go.mod and go.sum to remove unused dependencies and add new ones 2026-04-22 00:13:35 +00:00
GitHub Actions
5db3f7046c chore: add accessibility test suite documentation and baseline expiration dates 2026-04-22 00:13:35 +00:00
GitHub Actions
b59a788101 chore: include accessibility scans in non-security CI shards
Add automated accessibility suite execution to the standard non-security
end-to-end browser shards so regressions are caught during routine CI runs.

This change is necessary to enforce accessibility checks consistently across
Chromium, Firefox, and WebKit without creating a separate pipeline path.

Behavior impact:
- Non-security shard jobs now run accessibility tests alongside existing suites
- Security-specific job behavior remains unchanged
- Sharding logic remains unchanged, with only test scope expanded

Operational consideration:
- Monitor shard runtime balance after rollout; if sustained skew appears,
  split accessibility coverage into its own sharded workflow stage.
2026-04-22 00:13:35 +00:00
GitHub Actions
e7460f7e50 chore: update accessibility baseline and enhance loading waits for a11y tests 2026-04-22 00:13:35 +00:00
GitHub Actions
1e1727faa1 chore: add accessibility tests for domains, notifications, setup, and tasks pages 2026-04-22 00:13:35 +00:00
GitHub Actions
0c87c350e5 chore: add accessibility tests for security and uptime pages 2026-04-22 00:13:35 +00:00
GitHub Actions
03101012b9 chore: add accessibility tests for various pages including certificates, dashboard, dns providers, login, proxy hosts, and settings 2026-04-22 00:13:35 +00:00
GitHub Actions
5f855ea779 chore: add accessibility testing support with @axe-core/playwright and related utilities 2026-04-22 00:13:35 +00:00
GitHub Actions
a74d10d138 doc: Integrate @axe-core/playwright for Automated Accessibility Testing
Co-authored-by: Copilot <copilot@github.com>
2026-04-22 00:13:35 +00:00
Jeremy
515a95aaf1 Merge pull request #968 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-04-21 20:08:35 -04:00
renovate[bot]
1bcb4de6f8 fix(deps): update non-major-updates 2026-04-21 22:49:48 +00:00
Jeremy
07764db43e Merge pull request #966 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update non-major-updates (feature/beta-release)
2026-04-21 09:12:51 -04:00
renovate[bot]
54f32c03d0 chore(deps): update non-major-updates 2026-04-21 12:38:30 +00:00
Jeremy
c983250327 Merge pull request #965 from Wikid82/development
Propagate changes from development into feature/beta-release
2026-04-20 20:57:07 -04:00
Jeremy
2308f372d7 Merge pull request #964 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-04-20 17:56:55 -04:00
Jeremy
d68001b949 Merge pull request #963 from Wikid82/main
Propagate changes from main into development
2026-04-20 17:56:25 -04:00
Jeremy
a599623ea9 Merge branch 'development' into main 2026-04-20 17:55:51 -04:00
renovate[bot]
96f0be19a4 fix(deps): update non-major-updates 2026-04-20 21:45:50 +00:00
Jeremy
0f0a442d74 Merge pull request #962 from Wikid82/hotfix/ci
fix(ci): shift GeoLite2 update to Sunday targeting development branch
2026-04-20 12:56:13 -04:00
Jeremy
c1470eaac0 Merge pull request #961 from Wikid82/development
Propagate changes from development into feature/beta-release
2026-04-20 12:37:40 -04:00
GitHub Actions
2123fbca77 fix(ci): shift GeoLite2 update to Sunday targeting development branch
Co-authored-by: Copilot <copilot@github.com>
2026-04-20 16:35:02 +00:00
Jeremy
a8cd4bf34c Merge branch 'feature/beta-release' into development 2026-04-20 12:17:15 -04:00
Jeremy
02911109ef Merge pull request #960 from Wikid82/main
Propagate changes from main into development
2026-04-20 08:50:29 -04:00
GitHub Actions
2bad9fec53 fix: make URL preview invite modal test deterministic 2026-04-20 12:48:33 +00:00
Jeremy
54ce6f677c Merge pull request #959 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-04-20 08:34:32 -04:00
Jeremy
26a75f5fe3 Merge branch 'development' into main 2026-04-20 08:26:40 -04:00
Jeremy
ad7704c1df Merge branch 'feature/beta-release' into renovate/feature/beta-release-non-major-updates 2026-04-20 08:02:55 -04:00
Jeremy
877fee487b Merge pull request #958 from Wikid82/bot/update-geolite2-checksum
chore(docker): update GeoLite2-Country.mmdb checksum
2026-04-20 07:57:00 -04:00
GitHub Actions
330ccae82f fix: update vulnerability suppression for buger/jsonparser to reflect upstream fix availability 2026-04-20 11:56:26 +00:00
renovate[bot]
0a5bb296a9 fix(deps): update non-major-updates 2026-04-20 11:56:08 +00:00
GitHub Actions
437a35bd47 fix: replace div with button for close action in whitelist delete modal
Co-authored-by: Copilot <copilot@github.com>
2026-04-20 11:29:10 +00:00
GitHub Actions
612d3655fa fix: improve IP normalization in normalizeIPOrCIDR function
Co-authored-by: Copilot <copilot@github.com>
2026-04-20 11:27:56 +00:00
GitHub Actions
38cdc5d9d0 fix(deps): update @oxc-project/types and @rolldown dependencies to version 0.126.0 and 1.0.0-rc.16 respectively 2026-04-20 11:16:56 +00:00
GitHub Actions
816124634b fix(deps): update @oxc-parser dependencies to version 0.126.0 and remove unused packages 2026-04-20 11:16:20 +00:00
GitHub Actions
2b2f3c876b chore: fix Renovate lookup failure for google/uuid dependency 2026-04-20 11:02:31 +00:00
Jeremy
20f2624653 Merge pull request #957 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-04-20 06:51:03 -04:00
Wikid82
6509bb5d1b chore(docker): update GeoLite2-Country.mmdb checksum
Automated checksum update for GeoLite2-Country.mmdb database.

Old: b018842033872f19ed9ccefb863ec954f8024db2ae913d0d4ea14e35ace4eba1
New: 62049119bd084e19fff4689bebe258f18a5f27a386e6d26ba5180941b613fc2b

Auto-generated by: .github/workflows/update-geolite2.yml
2026-04-20 02:58:45 +00:00
Jeremy
e8724c5edc Merge branch 'feature/beta-release' into renovate/feature/beta-release-non-major-updates 2026-04-19 17:13:04 -04:00
GitHub Actions
2c284bdd49 test: add tests for handling empty UUID in DeleteWhitelist and invalid CIDR in Add method 2026-04-19 21:11:14 +00:00
GitHub Actions
db1e77ceb3 test(coverage): cover all modified lines for 100% patch coverage vs origin/main
- Add domains field to certificate mock to exercise per-domain loop
  in Dashboard component, covering the previously untested branch
- Extend CrowdSec whitelist test suite with backdrop-click close test
  to cover the dialog dismissal handler
- Remove duplicate describe blocks introduced when whitelist API tests
  were appended to crowdsec.test.ts, resolving ESLint vitest/no-identical-title
  errors that were blocking pre-commit hooks
2026-04-19 21:08:26 +00:00
GitHub Actions
df5e69236a fix(deps): update dependencies for improved stability and performance 2026-04-19 21:03:48 +00:00
renovate[bot]
a3259b042d fix(deps): update non-major-updates 2026-04-19 17:10:33 +00:00
GitHub Actions
f5e7c2bdfc fix(test): resolve CrowdSec card title lookup in Security test mock
The Security component renders the CrowdSec card title using the nested
translation key 'security.crowdsec.title', but the test mock only had the
flat key 'security.crowdsec'. The mock fallback returns the key string
itself when a lookup misses, causing getByText('CrowdSec') to find nothing.

Added 'security.crowdsec.title' to the securityTranslations map so the
mock resolves to the expected 'CrowdSec' string, matching the component's
actual t() call and allowing the title assertion to pass.
2026-04-18 01:39:06 +00:00
GitHub Actions
0859ab31ab fix(deps): update modernc.org/sqlite to version 1.49.1 for improved functionality 2026-04-18 01:36:58 +00:00
GitHub Actions
c02219cc92 fix(deps): update @asamuzakjp/dom-selector, @humanfs/core, @humanfs/node, and hasown to latest versions; add @humanfs/types dependency 2026-04-18 01:35:43 +00:00
GitHub Actions
d73b3aee5c fix(deps): update @humanfs/core and @humanfs/node to latest versions and add @humanfs/types dependency 2026-04-18 01:34:43 +00:00
Jeremy
80eb91e9a1 Merge pull request #956 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-04-17 21:33:31 -04:00
renovate[bot]
aa6c751007 fix(deps): update non-major-updates 2026-04-17 20:39:46 +00:00
GitHub Actions
1af786e7c8 fix: update eslint-plugin-react-hooks and typescript to latest versions for improved compatibility 2026-04-16 23:53:11 +00:00
GitHub Actions
c46c1976a2 fix: update typescript to version 6.0.3 for improved functionality and security 2026-04-16 23:52:39 +00:00
GitHub Actions
3b3ea83ecd chore: add database error handling tests for whitelist service and handler 2026-04-16 23:51:01 +00:00
GitHub Actions
5980a8081c fix: improve regex for delete button name matching in CrowdSec IP Whitelist tests 2026-04-16 14:12:07 +00:00
GitHub Actions
55f64f8050 fix: update translation keys for CrowdSec security titles and badges 2026-04-16 14:07:36 +00:00
GitHub Actions
983ae34147 fix(docker): persist CrowdSec LAPI database across container rebuilds 2026-04-16 14:04:15 +00:00
GitHub Actions
4232c0a8ee fix: update benchmark-action/github-action-benchmark to v1.22.0 and mlugg/setup-zig to v2.2.1 for improved security and functionality 2026-04-16 13:34:36 +00:00
GitHub Actions
402a8b3105 fix: update electron-to-chromium, eslint-plugin-sonarjs, minimatch, and ts-api-utils to latest versions 2026-04-16 13:34:36 +00:00
GitHub Actions
f46bb838ca feat: add QA audit report for CrowdSec IP Whitelist Management 2026-04-16 13:34:36 +00:00
GitHub Actions
3d0179a119 fix: update @asamuzakjp/css-color and @asamuzakjp/dom-selector to latest versions and add @asamuzakjp/generational-cache dependency 2026-04-16 13:34:36 +00:00
GitHub Actions
557b33dc73 fix: update docker/go-connections dependency to v0.7.0 2026-04-16 13:34:36 +00:00
GitHub Actions
2a1652d0b1 feat: add IP whitelist management details to architecture documentation 2026-04-16 13:34:36 +00:00
GitHub Actions
f0fdf9b752 test: update response key for whitelist entries and add validation test for missing fields 2026-04-16 13:34:36 +00:00
GitHub Actions
973efd6412 fix: initialize WhitelistSvc only if db is not nil and update error message in AddWhitelist handler 2026-04-16 13:34:36 +00:00
GitHub Actions
028342c63a fix: update JSON response key for whitelist entries in ListWhitelists handler 2026-04-16 13:34:36 +00:00
GitHub Actions
eb9b907ba3 feat: add end-to-end tests for CrowdSec IP whitelist management 2026-04-16 13:34:36 +00:00
GitHub Actions
aee0eeef82 feat: add unit tests for useCrowdSecWhitelist hooks 2026-04-16 13:34:36 +00:00
GitHub Actions
c977cf6190 feat: add whitelist management functionality to CrowdSecConfig 2026-04-16 13:34:36 +00:00
GitHub Actions
28bc73bb1a feat: add whitelist management hooks for querying and mutating whitelist entries 2026-04-16 13:34:36 +00:00
GitHub Actions
19719693b0 feat: add unit tests for CrowdSecWhitelistService and CrowdsecHandler 2026-04-16 13:34:36 +00:00
GitHub Actions
a243066691 feat: regenerate whitelist YAML on CrowdSec startup 2026-04-16 13:34:36 +00:00
GitHub Actions
741a59c333 feat: add whitelist management endpoints to CrowdsecHandler 2026-04-16 13:34:36 +00:00
GitHub Actions
5642a37c44 feat: implement CrowdSecWhitelistService for managing IP/CIDR whitelists 2026-04-16 13:34:36 +00:00
GitHub Actions
1726a19cb6 feat: add CrowdSecWhitelist model and integrate into API route registration 2026-04-16 13:34:36 +00:00
GitHub Actions
40090cda23 feat: add installation of crowdsecurity/whitelists parser 2026-04-16 13:34:36 +00:00
Jeremy
9945fac150 Merge branch 'development' into feature/beta-release 2026-04-16 09:33:49 -04:00
Jeremy
9c416599f8 Merge pull request #955 from Wikid82/renovate/development-non-major-updates
chore(deps): update node.js to 8510330 (development)
2026-04-16 09:33:22 -04:00
Jeremy
abf88ab4cb Merge pull request #954 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update non-major-updates (feature/beta-release)
2026-04-16 09:33:04 -04:00
renovate[bot]
34903cdd49 chore(deps): update node.js to 8510330 2026-04-16 13:26:43 +00:00
renovate[bot]
98c720987d chore(deps): update non-major-updates 2026-04-16 13:26:37 +00:00
Jeremy
1bd7eab223 Merge pull request #953 from Wikid82/development
Propagate changes from development into feature/beta-release
2026-04-16 09:25:43 -04:00
Jeremy
080e17d85a Merge pull request #951 from Wikid82/main
chore(config): migrate config .github/renovate.json
2026-04-15 13:23:05 -04:00
Jeremy
a059edf60d Merge pull request #950 from Wikid82/main
chore(config): migrate config .github/renovate.json
2026-04-15 13:22:15 -04:00
GitHub Actions
0a3b64ba5c fix: correct misplaced env block in propagate-changes workflow 2026-04-15 17:19:19 +00:00
Jeremy
8ee0d0403a Merge pull request #949 from Wikid82/renovate/migrate-config
chore(config): migrate Renovate config
2026-04-15 13:07:10 -04:00
renovate[bot]
9dab9186e5 chore(config): migrate config .github/renovate.json 2026-04-15 17:05:08 +00:00
Jeremy
c63e4a3d6b Merge pull request #928 from Wikid82/feature/beta-release
feat: Custom Certificate Upload & Management
2026-04-15 12:54:04 -04:00
GitHub Actions
0e8ff1bc2a fix(deps): update @napi-rs/wasm-runtime and postcss to latest versions 2026-04-15 16:09:12 +00:00
Jeremy
683967bbfc Merge pull request #948 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-04-15 12:05:15 -04:00
renovate[bot]
15947616a9 fix(deps): update non-major-updates 2026-04-15 16:02:03 +00:00
GitHub Actions
813985a903 fix(dependencies): update mongo-driver to v2.5.1 2026-04-15 11:38:35 +00:00
GitHub Actions
bd48c17aab chore: update dependencies for prettier and std-env in package-lock.json 2026-04-15 11:37:28 +00:00
GitHub Actions
8239a94938 chore: Add tests for CertificateList and CertificateUploadDialog components
- Implement test to deselect a row checkbox in CertificateList by clicking it a second time.
- Add test to close detail dialog via the close button in CertificateList.
- Add test to close export dialog via the cancel button in CertificateList.
- Add test to show KEY format badge when a .key file is uploaded in CertificateUploadDialog.
- Add test to ensure no format badge is shown for unknown file extensions in CertificateUploadDialog.
2026-04-15 11:35:10 +00:00
GitHub Actions
fb8d80f6a3 fix: correct CertificateUploadDialog tests to provide required key file 2026-04-14 20:40:26 +00:00
GitHub Actions
8090c12556 feat(proxy-host): enhance certificate handling and update form integration 2026-04-14 20:35:11 +00:00
GitHub Actions
0e0d42c9fd fix(certificates): mark key file as aria-required for PEM/DER cert uploads 2026-04-14 19:10:57 +00:00
GitHub Actions
14b48f23b6 fix: add key file requirement message for PEM/DER certificates in CertificateUploadDialog 2026-04-14 16:35:37 +00:00
GitHub Actions
0c0adf0e5a fix: refactor context handling in Register tests for improved cleanup 2026-04-14 16:33:54 +00:00
GitHub Actions
135edd208c fix: update caniuse-lite to version 1.0.30001788 for improved compatibility 2026-04-14 12:58:15 +00:00
GitHub Actions
81a083a634 fix: resolve CI test failures and close patch coverage gaps 2026-04-14 12:42:22 +00:00
GitHub Actions
149a2071c3 fix: update electron-to-chromium to version 1.5.336 for improved compatibility 2026-04-14 02:35:05 +00:00
GitHub Actions
027a1b1f18 fix: replace fireEvent with userEvent for file uploads in CertificateUploadDialog tests 2026-04-14 02:33:25 +00:00
GitHub Actions
7adf39a6a0 fix: update axe-core to version 4.11.3 for improved functionality and security 2026-04-14 02:33:25 +00:00
Jeremy
5408ebc95b Merge pull request #947 from Wikid82/renovate/feature/beta-release-actions-upload-pages-artifact-5.x
chore(deps): update actions/upload-pages-artifact action to v5 (feature/beta-release)
2026-04-13 22:32:42 -04:00
Jeremy
92a90bb8a1 Merge pull request #946 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-04-13 22:32:26 -04:00
renovate[bot]
6391532b2d fix(deps): update non-major-updates 2026-04-14 01:08:04 +00:00
renovate[bot]
a161163508 chore(deps): update actions/upload-pages-artifact action to v5 2026-04-13 20:32:41 +00:00
GitHub Actions
5b6bf945d9 fix: add key_file validation for PEM/DER uploads and resolve CI test failures 2026-04-13 19:56:35 +00:00
GitHub Actions
877a32f180 fix: enhance form validation for certificate upload by adding required attributes and adjusting test logic 2026-04-13 17:31:05 +00:00
GitHub Actions
1fe8a79ea3 fix: update @typescript-eslint packages to version 8.58.2 and undici to version 7.25.0 2026-04-13 17:29:26 +00:00
GitHub Actions
7c8e8c001c fix: enhance error handling in ConvertPEMToPFX for empty certificate cases 2026-04-13 14:12:47 +00:00
GitHub Actions
29c56ab283 fix: add context parameter to route registration functions for improved lifecycle management 2026-04-13 14:12:47 +00:00
GitHub Actions
0391f2b3e3 fix: add PFX password parameter to ExportCertificate method and update tests 2026-04-13 14:12:47 +00:00
GitHub Actions
942f585dd1 fix: improve error response format in certificate validation 2026-04-13 14:12:47 +00:00
GitHub Actions
3005db6943 fix: remove unnecessary string checks for key file in Upload method 2026-04-13 14:12:47 +00:00
GitHub Actions
f3c33dc81b fix: update golang.org/x/term to v0.42.0 for compatibility improvements 2026-04-13 14:12:47 +00:00
Jeremy
44e2bdec95 Merge branch 'development' into feature/beta-release 2026-04-13 09:25:51 -04:00
Jeremy
d71fc0b95f Merge pull request #945 from Wikid82/renovate/development-pin-dependencies
chore(deps): pin dependencies (development)
2026-04-13 09:18:48 -04:00
renovate[bot]
f295788ac1 chore(deps): pin dependencies 2026-04-13 13:17:54 +00:00
GitHub Actions
c19aa55fd7 chore: update package-lock.json to upgrade dependencies for improved stability 2026-04-13 13:10:40 +00:00
GitHub Actions
ea3d93253f fix: update CADDY_SECURITY_VERSION to 1.1.62 for improved security 2026-04-13 13:10:40 +00:00
Jeremy
114dca89c6 Merge pull request #944 from Wikid82/renovate/feature/beta-release-major-7-github-artifact-actions
chore(deps): update actions/upload-artifact action to v7 (feature/beta-release)
2026-04-13 09:05:00 -04:00
Jeremy
c7932fa1d9 Merge pull request #942 from Wikid82/renovate/feature/beta-release-actions-setup-go-6.x
chore(deps): update actions/setup-go action to v6 (feature/beta-release)
2026-04-13 09:03:23 -04:00
renovate[bot]
f0ffc27ca7 chore(deps): update actions/upload-artifact action to v7 2026-04-13 13:02:54 +00:00
Jeremy
4dfcf70c08 Merge pull request #941 from Wikid82/renovate/feature/beta-release-actions-github-script-9.x
chore(deps): update actions/github-script action to v9 (feature/beta-release)
2026-04-13 09:02:37 -04:00
Jeremy
71b34061d9 Merge pull request #940 from Wikid82/renovate/feature/beta-release-actions-checkout-6.x
chore(deps): update actions/checkout action to v6 (feature/beta-release)
2026-04-13 09:02:14 -04:00
renovate[bot]
368130b07a chore(deps): update actions/setup-go action to v6 2026-04-13 13:01:36 +00:00
renovate[bot]
85216ba6e0 chore(deps): update actions/github-script action to v9 2026-04-13 13:01:30 +00:00
renovate[bot]
06aacdee98 chore(deps): update actions/checkout action to v6 2026-04-13 13:01:24 +00:00
Jeremy
ef44ae40ec Merge branch 'development' into feature/beta-release 2026-04-13 08:49:52 -04:00
Jeremy
26ea2e9da1 Merge pull request #937 from Wikid82/main
Propagate changes from main into development
2026-04-13 08:49:17 -04:00
Jeremy
b90da3740c Merge pull request #936 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update renovatebot/github-action action to v46.1.9 (feature/beta-release)
2026-04-13 08:48:48 -04:00
Jeremy
83b361ae57 Merge pull request #938 from Wikid82/nightly
Weekly: Promote nightly to main (2026-04-13)
2026-04-13 08:48:06 -04:00
GitHub Actions
0ae1dc998a test: update certificate deletion tests to use string UUIDs instead of integers 2026-04-13 12:04:47 +00:00
Jeremy
44f475778f Merge branch 'feature/beta-release' into renovate/feature/beta-release-non-major-updates 2026-04-13 00:42:41 -04:00
Jeremy
7bd3a73bcf Merge pull request #935 from Wikid82/bot/update-geolite2-checksum
chore(docker): update GeoLite2-Country.mmdb checksum
2026-04-13 00:42:15 -04:00
GitHub Actions
48f6b7a12b fix: update Dockerfile to include musl and musl-utils in apk upgrade for improved compatibility 2026-04-13 04:40:02 +00:00
renovate[bot]
122e1fc20b chore(deps): update renovatebot/github-action action to v46.1.9 2026-04-13 04:38:53 +00:00
GitHub Actions
850550c5da test: update common name display test to match exact text 2026-04-13 04:38:26 +00:00
GitHub Actions
3b4fa064d6 test: add end-to-end tests for certificate export dialog functionality 2026-04-13 04:32:26 +00:00
GitHub Actions
78a9231c8a chore: add test_output.txt to .gitignore to exclude test output files from version control 2026-04-13 04:24:16 +00:00
GitHub Actions
e88a4c7982 chore: update package-lock.json to remove unused dependencies and improve overall package management 2026-04-13 04:10:16 +00:00
GitHub Actions
9c056faec7 fix: downgrade versions of css-color, brace-expansion, baseline-browser-mapping, and electron-to-chromium for compatibility 2026-04-13 04:07:49 +00:00
GitHub Actions
e865fa2b8b chore: update package.json and package-lock.json to include vitest and coverage dependencies 2026-04-13 04:03:30 +00:00
GitHub Actions
e1bc648dfc test: add certificate feature unit tests and null-safety fix
Add comprehensive unit tests for the certificate upload, export,
and detail management feature:

- CertificateExportDialog: 21 tests covering format selection,
  blob download, error handling, and password-protected exports
- CertificateUploadDialog: 23 tests covering file validation,
  format detection, drag-and-drop, and upload flow
- CertificateDetailDialog: 19 tests covering detail display,
  loading state, missing fields, and branch coverage
- CertificateChainViewer: 8 tests covering chain visualization
- CertificateValidationPreview: 16 tests covering validation display
- FileDropZone: 18 tests covering drag-and-drop interactions
- useCertificates hooks: 10 tests covering all React Query hooks
- certificates API: 7 new tests for previously uncovered endpoints

Fix null-safety issue in ProxyHosts where cert.domains could be
undefined, causing a runtime error on split().

Frontend patch coverage: 90.6%, overall lines: 89.09%
2026-04-13 04:02:31 +00:00
GitHub Actions
9d8d97e556 fix: update @csstools/css-calc, @csstools/css-color-parser, @tanstack/query-core, globals, builtin-modules, knip, and undici to latest versions for improved functionality and security 2026-04-13 04:02:31 +00:00
GitHub Actions
9dc55675ca fix: update Coraza Caddy version to 2.5.0 for compatibility 2026-04-13 04:01:31 +00:00
GitHub Actions
30c9d735aa feat: add certificate export and upload dialogs
- Implemented CertificateExportDialog for exporting certificates in various formats (PEM, PFX, DER) with options to include private keys and set passwords.
- Created CertificateUploadDialog for uploading certificates, including validation and support for multiple file types (certificates, private keys, chain files).
- Updated DeleteCertificateDialog to use 'domains' instead of 'domain' for consistency.
- Refactored BulkDeleteCertificateDialog and DeleteCertificateDialog tests to accommodate changes in certificate structure.
- Added FileDropZone component for improved file upload experience.
- Enhanced translation files with new keys for certificate management features.
- Updated Certificates page to utilize the new CertificateUploadDialog and clean up the upload logic.
- Adjusted Dashboard and ProxyHosts pages to reflect changes in certificate data structure.
2026-04-13 04:01:31 +00:00
GitHub Actions
e49ea7061a fix: add go-pkcs12 v0.7.1 for PKCS#12 support 2026-04-13 04:01:31 +00:00
GitHub Actions
5c50d8b314 fix: update brace-expansion version to 1.1.14 for improved compatibility 2026-04-13 04:01:30 +00:00
Wikid82
00ba5b3650 chore(docker): update GeoLite2-Country.mmdb checksum
Automated checksum update for GeoLite2-Country.mmdb database.

Old: f5e80a9a3129d46e75c8cccd66bfac725b0449a6c89ba5093a16561d58f20bda
New: b018842033872f19ed9ccefb863ec954f8024db2ae913d0d4ea14e35ace4eba1

Auto-generated by: .github/workflows/update-geolite2.yml
2026-04-13 02:59:03 +00:00
Jeremy
af95c1bdb3 Merge pull request #934 from Wikid82/renovate/feature/beta-release-softprops-action-gh-release-3.x
chore(deps): update softprops/action-gh-release action to v3 (feature/beta-release)
2026-04-12 21:14:11 -04:00
renovate[bot]
01e3d910f1 chore(deps): update softprops/action-gh-release action to v3 2026-04-13 01:12:42 +00:00
Jeremy
1230694f55 Merge pull request #933 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-04-12 21:06:36 -04:00
renovate[bot]
77f15a225f fix(deps): update non-major-updates 2026-04-12 16:50:55 +00:00
Jeremy
d75abb80d1 Merge pull request #932 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-04-11 16:19:08 -04:00
GitHub Actions
42bc897610 fix: enhance certificate deletion handling with UUID validation and logging improvements 2026-04-11 17:54:42 +00:00
renovate[bot]
b15f7c3fbc fix(deps): update non-major-updates 2026-04-11 17:47:55 +00:00
GitHub Actions
bb99dacecd fix: update zlib and add libcrypto3 and libssl3 for improved security 2026-04-11 17:33:44 +00:00
GitHub Actions
4b925418f2 feat: Add certificate validation service with parsing and metadata extraction
- Implemented certificate parsing for PEM, DER, and PFX formats.
- Added functions to validate key matches and certificate chains.
- Introduced metadata extraction for certificates including common name, domains, and issuer organization.
- Created unit tests for all new functionalities to ensure reliability and correctness.
2026-04-11 07:17:45 +00:00
GitHub Actions
9e82efd23a fix: downgrade delve version from 1.26.2 to 1.26.1 for compatibility 2026-04-11 00:11:25 +00:00
GitHub Actions
8f7c10440c chore: align agent and instruction files with single-PR commit-slicing model
- Rewrote commit slicing guidance in Management, Planning, and subagent
  instruction files to enforce one-feature-one-PR with ordered logical commits
- Removed multi-PR branching logic from the execution workflow
- Prevents partial feature merges that cause user confusion on self-hosted tools
- All cross-references now use "Commit N" instead of "PR-N"
2026-04-10 23:41:05 +00:00
GitHub Actions
a439e1d467 fix: add git to Dockerfile dependencies for improved build capabilities 2026-04-10 21:03:54 +00:00
Jeremy
718a957ad9 Merge branch 'development' into feature/beta-release 2026-04-10 16:53:27 -04:00
GitHub Actions
059ff9c6b4 fix: update Go version from 1.26.1 to 1.26.2 in Dockerfile and documentation for security improvements 2026-04-10 20:48:46 +00:00
Jeremy
062b86642d Merge pull request #927 from Wikid82/feature/beta-release
fix: dependency updates, CVE suppression management, and Renovate version constraints
2026-04-10 16:32:51 -04:00
GitHub Actions
a5724aecf9 fix: update indirect dependencies for golang.org/x/arch, modernc.org/libc, and modernc.org/sqlite to latest versions 2026-04-10 19:22:04 +00:00
GitHub Actions
53dccbe82b fix: update baseline-browser-mapping and call-bind versions for security and compatibility 2026-04-10 19:22:04 +00:00
Jeremy
8d6645415a Merge pull request #926 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update non-major-updates (feature/beta-release)
2026-04-10 15:21:01 -04:00
renovate[bot]
4cfcc9aa02 chore(deps): update non-major-updates 2026-04-10 19:18:28 +00:00
Jeremy
5d384e4afa Merge pull request #925 from Wikid82/renovate/feature/beta-release-actions-github-script-9.x
chore(deps): update actions/github-script action to v9 (feature/beta-release)
2026-04-10 15:17:21 -04:00
Jeremy
5bf25fdebc Merge pull request #924 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-04-10 15:17:05 -04:00
Jeremy
253d1ddd29 Merge branch 'feature/beta-release' into renovate/feature/beta-release-actions-github-script-9.x 2026-04-10 11:58:09 -04:00
Jeremy
5eab41b559 Merge branch 'feature/beta-release' into renovate/feature/beta-release-non-major-updates 2026-04-10 11:57:50 -04:00
GitHub Actions
a076bb3265 chore(security): re-evaluate overdue CVE suppressions 2026-04-10 15:56:43 +00:00
Jeremy
9c85d9e737 Merge branch 'feature/beta-release' into renovate/feature/beta-release-actions-github-script-9.x 2026-04-10 11:41:55 -04:00
Jeremy
1de4ce6729 Merge branch 'feature/beta-release' into renovate/feature/beta-release-non-major-updates 2026-04-10 11:41:36 -04:00
GitHub Actions
8e0f88e8bd fix: add suppression for CVE-2026-32286 due to pgproto3/v2 buffer overflow vulnerability 2026-04-10 15:39:52 +00:00
GitHub Actions
36460a884e fix: enforce version constraints for pgx and go-jose modules to maintain compatibility 2026-04-10 15:26:36 +00:00
renovate[bot]
585ae9494d chore(deps): update actions/github-script action to v9 2026-04-10 15:11:56 +00:00
renovate[bot]
ed9d6fe5d8 fix(deps): update non-major-updates 2026-04-10 15:11:47 +00:00
Jeremy
f0147b1315 Merge pull request #921 from Wikid82/feature/beta-release
fix: resolve 5 HIGH-severity CVEs blocking nightly container image scan
2026-04-09 21:13:01 -04:00
GitHub Actions
615e5a95f5 fix: downgrade pgx/v4 to v4.18.3 to address buffer overflow vulnerability 2026-04-09 19:09:25 +00:00
Jeremy
5b85d18217 Merge pull request #923 from Wikid82/renovate/feature/beta-release-github.com-jackc-pgx-v4-5.x
chore(deps): update module github.com/jackc/pgx/v4 to v5 (feature/beta-release)
2026-04-09 14:31:42 -04:00
renovate[bot]
f05c24dd66 chore(deps): update module github.com/jackc/pgx/v4 to v5 2026-04-09 18:24:32 +00:00
GitHub Actions
fd11279aa3 fix: update security policy for CVE-2026-31790 and CVE-2026-2673 vulnerabilities 2026-04-09 17:59:56 +00:00
GitHub Actions
59282952b0 fix(ci): provide Go 1.26.2 toolchain for Renovate dependency lookups 2026-04-09 17:55:51 +00:00
GitHub Actions
8742c76d52 fix: add Grype ignore for unfixed Alpine OpenSSL CVE-2026-31790
No upstream fix available for libcrypto3/libssl3 in Alpine 3.23.3.
Accepted risk documented in SECURITY.md. Monitoring Alpine security
advisories for patch availability.
2026-04-09 17:52:04 +00:00
Jeremy
9c0193e812 Merge pull request #922 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-04-09 13:42:52 -04:00
renovate[bot]
64465e1cd9 fix(deps): update non-major-updates 2026-04-09 17:27:46 +00:00
GitHub Actions
580e20d573 fix: resolve 5 HIGH-severity CVEs blocking nightly container image scan
Patch vulnerable transitive dependencies across all three compiled
binaries in the Docker image (backend, Caddy, CrowdSec):

- go-jose/v3 and v4: JOSE/JWT validation bypass (CVE-2026-34986)
- otel/sdk: resource leak in OpenTelemetry SDK (CVE-2026-39883)
- pgproto3/v2: buffer overflow via pgx/v4 bump (CVE-2026-32286)
- AWS SDK v2: event stream injection in CrowdSec deps (GHSA-xmrv-pmrh-hhx2)
- OTel HTTP exporters: request smuggling (CVE-2026-39882)
- gRPC: bumped to v1.80.0 for transitive go-jose/v4 resolution

All Dockerfile patches include Renovate annotations for automated
future tracking. Renovate config extended to cover Go version and
GitHub Action refs in skill example workflows, preventing version
drift in non-CI files. SECURITY.md updated with pre-existing Alpine
base image CVE (no upstream fix available).

Nightly Go stdlib CVEs (1.26.1) self-heal on next development sync;
example workflow pinned to 1.26.2 for correctness.
2026-04-09 17:24:25 +00:00
GitHub Actions
bb496daae3 fix(ci): improve health check for Charon container in nightly build 2026-04-09 14:08:19 +00:00
GitHub Actions
4cd568b0e5 fix(deps): update multiple dependencies in package-lock.json 2026-04-09 14:04:00 +00:00
GitHub Actions
efd70cd651 fix(deps): update golang.org/x/text to v0.36.0 and other dependencies 2026-04-09 14:01:05 +00:00
GitHub Actions
3d4a63b515 fix(go): update Go version to 1.26.2 2026-04-09 13:58:24 +00:00
Jeremy
42cec9e8c3 Merge pull request #919 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-04-09 09:41:24 -04:00
renovate[bot]
73565e0e0d fix(deps): update non-major-updates 2026-04-09 09:20:57 +00:00
Jeremy
6dddc5db43 Merge pull request #918 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-04-06 20:30:42 -04:00
renovate[bot]
ef90d1c0d7 fix(deps): update non-major-updates 2026-04-06 21:48:29 +00:00
Jeremy
0354f5cecf Merge pull request #917 from Wikid82/nightly
Weekly: Promote nightly to main (2026-04-06)
2026-04-06 12:14:47 -04:00
Jeremy
2d923246a9 Merge pull request #916 from Wikid82/development
Propagate changes from development into feature/beta-release
2026-04-06 01:24:35 -04:00
Jeremy
241c0d1b35 Merge pull request #914 from Wikid82/renovate/development-non-major-updates
chore(deps): update non-major-updates (development)
2026-04-06 01:08:26 -04:00
Jeremy
a9767baa69 Merge branch 'development' into renovate/development-non-major-updates 2026-04-06 01:08:07 -04:00
Jeremy
79f0080c80 Merge pull request #915 from Wikid82/main
Propagate changes from main into development
2026-04-06 01:07:49 -04:00
renovate[bot]
bfa6fc0920 chore(deps): update non-major-updates 2026-04-06 04:42:28 +00:00
Jeremy
c70c87386e Merge pull request #913 from Wikid82/bot/update-geolite2-checksum
chore(docker): update GeoLite2-Country.mmdb checksum
2026-04-06 00:38:12 -04:00
Jeremy
a5c6eb95c6 Merge pull request #887 from Wikid82/feature/beta-release
Feature: CrowdSec Dashboard Integration with Observable Metrics
2026-04-06 00:37:46 -04:00
Wikid82
f5ab2cddd8 chore(docker): update GeoLite2-Country.mmdb checksum
Automated checksum update for GeoLite2-Country.mmdb database.

Old: 7840f4b8891e7c866f948d4b020cdc12aeea51b09450b44ad96d1f14f6e32879
New: f5e80a9a3129d46e75c8cccd66bfac725b0449a6c89ba5093a16561d58f20bda

Auto-generated by: .github/workflows/update-geolite2.yml
2026-04-06 02:58:45 +00:00
GitHub Actions
47d306b44b fix(docker): ensure CrowdSec hub index and collections bootstrap on every startup 2026-04-05 05:16:26 +00:00
GitHub Actions
5e73ba7bd0 fix(security): add temporary ignore rules for transitive HIGH vulnerabilities 2026-04-05 04:18:54 +00:00
GitHub Actions
32a30434b1 fix(security): prevent client injection of enrichment fields on decisions 2026-04-05 02:51:54 +00:00
GitHub Actions
138426311f fix(models): prevent zero-date serialization for optional ExpiresAt 2026-04-05 02:51:54 +00:00
GitHub Actions
a8ef9dd6ce fix(crowdsec): use read lock for non-mutating cache lookups 2026-04-05 02:51:54 +00:00
GitHub Actions
b48794df14 fix(deps): update smol-toml version constraint to ensure compatibility 2026-04-05 02:51:54 +00:00
GitHub Actions
85a80568b2 fix(ci): load Grype ignore config in supply chain verification 2026-04-05 02:51:54 +00:00
GitHub Actions
fc0e31df56 fix(deps): update tldts and tldts-core to version 7.0.28 for compatibility improvements 2026-04-05 02:51:54 +00:00
Jeremy
cb4ae8367c Merge pull request #910 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update dependency tldts to ^7.0.28 (feature/beta-release)
2026-04-04 22:32:58 -04:00
Jeremy
de020d9901 Merge pull request #909 from Wikid82/renovate/feature/beta-release-react-i18next-17.x
fix(deps): update dependency react-i18next to v17 (feature/beta-release)
2026-04-04 22:24:07 -04:00
renovate[bot]
0634357ee9 fix(deps): update dependency tldts to ^7.0.28 2026-04-05 02:04:41 +00:00
renovate[bot]
9753a13001 fix(deps): update dependency react-i18next to v17 2026-04-04 01:09:32 +00:00
Jeremy
d0deef1537 Merge branch 'development' into feature/beta-release 2026-04-03 21:08:07 -04:00
Jeremy
4603b57224 Merge pull request #908 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-04-03 21:07:43 -04:00
Jeremy
bb64ca64e2 Merge branch 'feature/beta-release' into renovate/feature/beta-release-non-major-updates 2026-04-03 21:07:31 -04:00
Jeremy
ce4a9c5626 Merge pull request #896 from Wikid82/renovate/feature/beta-release-react-i18next-17.x
fix(deps): update dependency react-i18next to v17 (feature/beta-release)
2026-04-03 21:07:00 -04:00
renovate[bot]
b45861090d fix(deps): update non-major-updates 2026-04-04 00:58:06 +00:00
Jeremy
4a3f655a49 Merge pull request #907 from Wikid82/main
Propagate changes from main into development
2026-04-03 20:58:02 -04:00
Jeremy
29e069ac94 Merge branch 'feature/beta-release' into renovate/feature/beta-release-react-i18next-17.x 2026-04-03 20:56:19 -04:00
GitHub Actions
625fcf8e5c fix: update Trivy action version and extend vulnerability review dates in configuration files 2026-04-04 00:54:55 +00:00
GitHub Actions
2b8ed06c3c fix: remediate axios supply chain compromise and harden CI workflow permissions 2026-04-04 00:05:27 +00:00
GitHub Actions
34d73ad6ed fix: update dependencies for @emnapi/core, @emnapi/runtime, @emnapi/wasi-threads, @playwright/test, and dotenv for compatibility improvements 2026-04-03 23:20:41 +00:00
GitHub Actions
e06a8cb676 fix: update go-sqlite3 and other dependencies for compatibility and improvements 2026-04-03 22:57:25 +00:00
GitHub Actions
5ba8cd60c8 fix: add npmDedupe to postUpdateOptions for improved dependency management 2026-04-03 22:55:15 +00:00
GitHub Actions
29985714a3 fix: update CORAZA_CADDY_VERSION to 2.4.0 for compatibility improvements 2026-04-03 22:39:40 +00:00
GitHub Actions
64c9d7adbe fix: update CADDY_SECURITY_VERSION to 1.1.61 for security improvements 2026-04-03 22:38:28 +00:00
Jeremy
8d56760c64 Merge branch 'feature/beta-release' into renovate/feature/beta-release-react-i18next-17.x 2026-03-30 21:19:47 -04:00
Jeremy
087ae9cc0d Merge pull request #890 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-30 21:19:28 -04:00
Jeremy
35b003ae5e Merge branch 'feature/beta-release' into renovate/feature/beta-release-non-major-updates 2026-03-30 21:19:14 -04:00
Jeremy
cab3c68508 Merge pull request #895 from Wikid82/renovate/feature/beta-release-i18next-26.x
fix(deps): update dependency i18next to v26 (feature/beta-release)
2026-03-30 21:17:42 -04:00
Jeremy
b6558d4165 Merge pull request #894 from Wikid82/renovate/feature/beta-release-eslint-plugin-unicorn-64.x
chore(deps): update dependency eslint-plugin-unicorn to v64 (feature/beta-release)
2026-03-30 21:17:25 -04:00
Jeremy
64cbe5a74d Merge pull request #893 from Wikid82/renovate/feature/beta-release-eslint-markdown-8.x
chore(deps): update dependency @eslint/markdown to v8 (feature/beta-release)
2026-03-30 21:17:10 -04:00
Jeremy
1d3e60b4f8 Merge pull request #892 from Wikid82/renovate/feature/beta-release-codecov-codecov-action-6.x
chore(deps): update codecov/codecov-action action to v6 (feature/beta-release)
2026-03-30 21:16:50 -04:00
Jeremy
07e6ad2d09 Merge pull request #891 from Wikid82/renovate/feature/beta-release-actions-deploy-pages-5.x
chore(deps): update actions/deploy-pages action to v5 (feature/beta-release)
2026-03-30 21:16:33 -04:00
Jeremy
1911003db5 Merge pull request #888 from Wikid82/bot/update-geolite2-checksum
chore(docker): update GeoLite2-Country.mmdb checksum
2026-03-30 21:16:01 -04:00
renovate[bot]
543388b5a4 fix(deps): update non-major-updates 2026-03-31 01:08:59 +00:00
Jeremy
e2774cccf7 Merge branch 'feature/beta-release' into renovate/feature/beta-release-react-i18next-17.x 2026-03-30 18:42:13 -04:00
Jeremy
bf4dd17792 Merge branch 'feature/beta-release' into renovate/feature/beta-release-i18next-26.x 2026-03-30 18:41:56 -04:00
Jeremy
4abc29406f Merge branch 'feature/beta-release' into renovate/feature/beta-release-eslint-plugin-unicorn-64.x 2026-03-30 18:41:41 -04:00
Jeremy
b75f92a88b Merge branch 'feature/beta-release' into renovate/feature/beta-release-eslint-markdown-8.x 2026-03-30 18:41:22 -04:00
Jeremy
237a3a4d80 Merge branch 'feature/beta-release' into renovate/feature/beta-release-codecov-codecov-action-6.x 2026-03-30 18:40:59 -04:00
Jeremy
3e926298f2 Merge branch 'feature/beta-release' into renovate/feature/beta-release-actions-deploy-pages-5.x 2026-03-30 18:40:36 -04:00
GitHub Actions
e84df69cb6 fix: add vulnerability suppressions for Docker AuthZ plugin bypass and Moby privilege validation issues 2026-03-30 22:38:33 +00:00
GitHub Actions
0a43a76a4a fix: update CROWDSEC_VERSION to 1.7.7 for compatibility improvements 2026-03-30 22:20:37 +00:00
GitHub Actions
c852838644 fix: update CORAZA_CADDY_VERSION to 2.3.0 for compatibility improvements 2026-03-30 22:19:49 +00:00
GitHub Actions
9740ddb813 fix: update CADDY_SECURITY_VERSION to 1.1.57 for security improvements 2026-03-30 22:19:07 +00:00
renovate[bot]
5abd01f61c fix(deps): update dependency react-i18next to v17 2026-03-30 22:01:12 +00:00
renovate[bot]
e40a241d62 fix(deps): update dependency i18next to v26 2026-03-30 22:01:05 +00:00
renovate[bot]
a72e587d29 chore(deps): update dependency eslint-plugin-unicorn to v64 2026-03-30 22:00:58 +00:00
renovate[bot]
976ae0272b chore(deps): update dependency @eslint/markdown to v8 2026-03-30 22:00:51 +00:00
renovate[bot]
ccd3081d09 chore(deps): update codecov/codecov-action action to v6 2026-03-30 22:00:43 +00:00
renovate[bot]
844c800cd9 chore(deps): update actions/deploy-pages action to v5 2026-03-30 22:00:38 +00:00
Jeremy
ecf314b2e5 Merge branch 'main' into bot/update-geolite2-checksum 2026-03-30 17:56:36 -04:00
Jeremy
a78529e218 Merge pull request #889 from Wikid82/nightly
Weekly: Promote nightly to main (2026-03-30)
2026-03-30 17:56:21 -04:00
Wikid82
e32f3dfb57 chore(docker): update GeoLite2-Country.mmdb checksum
Automated checksum update for GeoLite2-Country.mmdb database.

Old: c6549807950f93f609d6433fa295fa517fbdec0ad975a4aafba69c136d5d2347
New: 7840f4b8891e7c866f948d4b020cdc12aeea51b09450b44ad96d1f14f6e32879

Auto-generated by: .github/workflows/update-geolite2.yml
2026-03-30 02:58:26 +00:00
GitHub Actions
e6c4e46dd8 chore: Refactor test setup for Gin framework
- Removed redundant `gin.SetMode(gin.TestMode)` calls from individual test files.
- Introduced a centralized `TestMain` function in `testmain_test.go` to set the Gin mode for all tests.
- Ensured consistent test environment setup across various handler test files.
2026-03-25 22:00:07 +00:00
GitHub Actions
f40fca844f fix: update CADDY_SECURITY_VERSION to 1.1.53 for security improvements 2026-03-25 20:47:46 +00:00
GitHub Actions
c7daa4ac46 chore(deps): update electron-to-chromium, lucide-react, and undici to latest versions 2026-03-25 19:36:52 +00:00
GitHub Actions
0a4ac41242 fix: update CADDY_SECURITY_VERSION to 1.1.52 for security improvements 2026-03-25 19:34:48 +00:00
GitHub Actions
3336aae2a0 chore: enforce local patch coverage as a blocking DoD gate
- Added ~40 backend tests covering uncovered branches in CrowdSec
  dashboard handlers (error paths, validation, export edge cases)
- Patch coverage improved from 81.5% to 98.3%, exceeding 90% threshold
- Fixed DoD ordering: coverage tests now run before the patch report
  (the report requires coverage artifacts as input)
- Rewrote the local patch coverage DoD step in both the Management agent
  and testing instructions to clarify purpose, prerequisites, required
  action on findings, and blocking gate semantics
- Eliminated ambiguous "advisory" language that allowed agents to skip
  acting on uncovered lines
2026-03-25 19:33:19 +00:00
GitHub Actions
1fe69c2a15 feat: add Top Attacking IPs chart component and integrate into CrowdSec configuration page
- Implemented TopAttackingIPsChart component for visualizing top attacking IPs.
- Created hooks for fetching CrowdSec dashboard data including summary, timeline, top IPs, scenarios, and alerts.
- Added tests for the new hooks to ensure data fetching works as expected.
- Updated translation files for new dashboard terms in multiple languages.
- Refactored CrowdSecConfig page to include a tabbed interface for configuration and dashboard views.
- Added end-to-end tests for CrowdSec dashboard functionality including tab navigation, data display, and interaction with time range and refresh features.
2026-03-25 17:19:15 +00:00
Jeremy
846eedeab0 Merge pull request #885 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update dependency knip to ^6.0.5 (feature/beta-release)
2026-03-25 08:33:19 -04:00
renovate[bot]
37c7c4aeb8 chore(deps): update dependency knip to ^6.0.5 2026-03-25 11:35:17 +00:00
Jeremy
548a2b6851 Merge pull request #883 from Wikid82/feature/beta-release
feat: add support for Ntfy notification provider
2026-03-25 07:32:51 -04:00
GitHub Actions
c64890b5a0 fix: update TRIGGER_PR_NUMBER formatting for consistency in workflow 2026-03-25 10:00:34 +00:00
GitHub Actions
664b440d70 fix: update Ntfy setup instructions for clarity and security token terminology 2026-03-25 09:58:38 +00:00
Jeremy
c929dfbe4a Merge branch 'development' into feature/beta-release 2026-03-25 05:14:17 -04:00
GitHub Actions
20e724f19c fix: update docker-build.yml to include 'development' branch in push triggers 2026-03-25 09:13:15 +00:00
GitHub Actions
a6deff77a7 fix(deps): update electron-to-chromium to version 1.5.323 for improved stability 2026-03-25 08:48:35 +00:00
GitHub Actions
8702d7b76d fix(deps): update CADDY_SECURITY_VERSION to 1.1.51 for security improvements 2026-03-25 04:10:05 +00:00
GitHub Actions
c9f4e42735 fix: update SECURITY.md with new vulnerability details and remediation plans 2026-03-25 04:05:15 +00:00
GitHub Actions
86023788aa feat: add support for Ntfy notification provider
- Updated the list of supported notification provider types to include 'ntfy'.
- Modified the notification settings UI to accommodate the Ntfy provider, including form fields for topic URL and access token.
- Enhanced localization files to include translations for Ntfy-related fields in German, English, Spanish, French, and Chinese.
- Implemented tests for the Ntfy notification provider, covering form rendering, CRUD operations, payload contracts, and security measures.
- Updated existing tests to account for the new Ntfy provider in various scenarios.
2026-03-24 21:04:54 +00:00
GitHub Actions
5a2b6fec9d fix(deps): update katex to v0.16.42 for improved functionality 2026-03-24 20:25:38 +00:00
GitHub Actions
d90dc5af98 fix(deps): update go-toml to v2.3.0 for improved compatibility 2026-03-24 20:10:02 +00:00
Jeremy
1d62a3da5f Merge pull request #882 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-24 13:45:56 -04:00
Jeremy
f237fa595a Merge pull request #873 from Wikid82/feature/beta-release
fix(certificates): allow deletion of expired and unused certificates
2026-03-24 13:45:08 -04:00
renovate[bot]
07ce79b439 fix(deps): update non-major-updates 2026-03-24 17:37:02 +00:00
Jeremy
77511b0994 Merge pull request #881 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-24 08:54:12 -04:00
GitHub Actions
246b83c72d chore: update package-lock.json for dependency version consistency 2026-03-24 12:08:22 +00:00
renovate[bot]
a7e4e12f32 fix(deps): update non-major-updates 2026-03-24 11:59:32 +00:00
Jeremy
91c1fa9d0f Merge pull request #879 from Wikid82/renovate/feature/beta-release-major-1-lucide-monorepo
fix(deps): update dependency lucide-react to v1 (feature/beta-release)
2026-03-24 07:57:18 -04:00
Jeremy
5a2698123e Merge pull request #878 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-24 07:53:22 -04:00
Jeremy
752e4dbd66 Merge branch 'feature/beta-release' into renovate/feature/beta-release-major-1-lucide-monorepo 2026-03-24 02:42:23 -04:00
Jeremy
f2769eca1a Merge branch 'feature/beta-release' into renovate/feature/beta-release-non-major-updates 2026-03-24 02:42:04 -04:00
Jeremy
e779041039 Merge branch 'development' into feature/beta-release 2026-03-24 02:41:29 -04:00
Jeremy
6c6c3f3373 Merge pull request #880 from Wikid82/main
Propagate changes from main into development
2026-03-24 02:41:00 -04:00
GitHub Actions
59adf32861 fix(deps): resolve Renovate lookup failure for geoip2-golang v2 module
Renovate could not resolve the Go module path
github.com/oschwald/geoip2-golang/v2 because the /v2 suffix is a Go
module convention, not a separate GitHub repository. Added a packageRules
entry with an explicit sourceUrl pointing to the actual upstream repo so
Renovate can correctly look up available versions.

No changes to application code, go.mod, or go.sum — the dependency was
already declared correctly.
2026-03-24 06:32:00 +00:00
renovate[bot]
55204289ec fix(deps): update dependency lucide-react to v1 2026-03-24 06:22:11 +00:00
renovate[bot]
95bf0b496d fix(deps): update non-major-updates 2026-03-24 06:20:22 +00:00
Jeremy
583633c74b Merge pull request #876 from Wikid82/bot/update-geolite2-checksum
chore(docker): update GeoLite2-Country.mmdb checksum
2026-03-24 02:18:43 -04:00
GitHub Actions
c822ba7582 chore: downgrade vitest and related packages to version 4.0.18 2026-03-24 01:52:48 +00:00
GitHub Actions
a5daaa5e8c fix: add missing name field in package-lock.json 2026-03-24 01:51:42 +00:00
GitHub Actions
6967c73eaf chore: update dependencies to latest versions
- Upgraded @tanstack/query-core and @tanstack/react-query from 5.95.0 to 5.95.2
- Updated @typescript-eslint packages from 8.57.1 to 8.57.2
- Bumped @vitest packages from 4.1.0 to 4.1.1
- Updated knip from 6.0.3 to 6.0.4
- Upgraded picomatch from 4.0.3 to 4.0.4 and from 2.3.1 to 2.3.2
- Updated react-router and react-router-dom from 7.13.1 to 7.13.2
- Bumped typescript from 6.0.1-rc to 6.0.2
2026-03-24 01:50:32 +00:00
GitHub Actions
602b0b0e2e chore: update package versions in package-lock.json for consistency 2026-03-24 01:50:02 +00:00
GitHub Actions
49b3e4e537 fix(tests): resolve i18n mock issues in BulkDeleteCertificateDialog tests
Removed local i18n mock to allow global mock to function correctly, updated assertions to use resolved English translations for better consistency in test outcomes.
2026-03-24 01:47:43 +00:00
GitHub Actions
ca477c48d4 chore: Enhance documentation for E2E testing:
- Added clarity and structure to README files, including recent updates and getting started sections.
- Improved manual verification documentation for CrowdSec authentication, emphasizing expected outputs and success criteria.
- Updated debugging guide with detailed output examples and automatic trace capture information.
- Refined best practices for E2E tests, focusing on efficient polling, locator strategies, and state management.
- Documented triage report for DNS Provider feature tests, highlighting issues fixed and test results before and after improvements.
- Revised E2E test writing guide to include when to use specific helper functions and patterns for better test reliability.
- Enhanced troubleshooting documentation with clear resolutions for common issues, including timeout and token configuration problems.
- Updated tests README to provide quick links and best practices for writing robust tests.
2026-03-24 01:47:22 +00:00
GitHub Actions
7d986f2821 chore: update package versions in package-lock.json for consistency 2026-03-23 13:14:48 +00:00
GitHub Actions
849c3513bb feat(i18n): add aria-label for bulk delete certificates in multiple languages 2026-03-23 05:46:49 +00:00
GitHub Actions
a707d8e67e feat(i18n): add localized provider labels for certificate management 2026-03-23 05:45:23 +00:00
GitHub Actions
3cacecde5a fx: replace getAuthToken function with getStorageStateAuthHeaders for improved auth handling 2026-03-23 05:42:02 +00:00
GitHub Actions
4bdc771cd4 feat: synchronize selected certificate IDs with available certificates on update 2026-03-23 05:39:37 +00:00
GitHub Actions
f13d95df0f fix: specify gotestsum version in workflows for consistency 2026-03-23 05:32:52 +00:00
GitHub Actions
73aecc60e8 fix(i18n): restore localized noteText in all non-English certificate locales
- The certificate section's noteText had previously been translated into
  Chinese, German, Spanish, and French but was inadvertently overwritten
  with an English string when the individual certificate delete feature
  was introduced.
- All four locales now carry properly translated text that also reflects
  the updated policy: expired or expiring production certificates that
  are not attached to a proxy host are now eligible for deletion.
- Newly introduced keys (deleteConfirmExpiring and other delete-related
  keys) remain as English placeholders pending professional translation,
  which is the established pattern for this project.
2026-03-23 05:24:58 +00:00
Wikid82
6fc4409513 chore(docker): update GeoLite2-Country.mmdb checksum
Automated checksum update for GeoLite2-Country.mmdb database.

Old: aa154fc6bcd712644de232a4abcdd07dac1f801308c0b6f93dbc2b375443da7b
New: c6549807950f93f609d6433fa295fa517fbdec0ad975a4aafba69c136d5d2347

Auto-generated by: .github/workflows/update-geolite2.yml
2026-03-23 02:57:35 +00:00
GitHub Actions
9ed698b236 feat: enhance certificate management with expiring status
- Update isInUse function to handle certificates without an ID.
- Modify isDeletable function to include 'expiring' status as deletable.
- Adjust CertificateList component to reflect changes in deletable logic.
- Update BulkDeleteCertificateDialog and DeleteCertificateDialog to handle expiring certificates.
- Add tests for expiring certificates in CertificateList and BulkDeleteCertificateDialog.
- Update translations for expiring certificates in multiple languages.
2026-03-23 02:23:08 +00:00
GitHub Actions
69736503ac feat: add BulkDeleteCertificateDialog component for bulk certificate deletion
- Implemented BulkDeleteCertificateDialog with confirmation and listing of certificates to be deleted.
- Added translations for bulk delete functionality in English, German, Spanish, French, and Chinese.
- Created unit tests for BulkDeleteCertificateDialog to ensure proper rendering and functionality.
- Developed end-to-end tests for bulk certificate deletion, covering selection, confirmation, and cancellation scenarios.
2026-03-23 00:07:59 +00:00
Jeremy
5b8941554b Merge pull request #875 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-22 18:00:57 -04:00
renovate[bot]
0bb7826ad5 fix(deps): update non-major-updates 2026-03-22 20:26:16 +00:00
GitHub Actions
bae55fb876 chore(ci): prevent test log truncation in backend coverage workflows
- Install gotestsum in CI so the coverage script uses compact
  pkgname-formatted output instead of go test -v, which produces
  massive verbose logs that exceed GitHub Actions' step log buffer
- Upload the full test output as a downloadable artifact on every
  run (including failures) so truncated logs never block debugging
- Aligns upload-artifact pin to v7.0.0 matching the rest of the repo
2026-03-22 18:49:02 +00:00
GitHub Actions
97255f84e6 fix: add tests for delete certificate functionality and error handling in CertificateList 2026-03-22 17:33:11 +00:00
Jeremy
174f1fe511 Merge pull request #874 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-22 12:00:19 -04:00
GitHub Actions
53fc2f1e78 fix: remove unused waitForToast import from certificate-delete.spec.ts 2026-03-22 14:29:31 +00:00
GitHub Actions
ef5e2e2ea2 fix: enhance setupAuditTestDB for proper database connection handling and documentation 2026-03-22 14:29:31 +00:00
renovate[bot]
b2c40345f8 fix(deps): update non-major-updates 2026-03-22 14:24:03 +00:00
Jeremy
a38de8518f Merge branch 'development' into feature/beta-release 2026-03-22 09:52:02 -04:00
GitHub Actions
a98e37b8b4 fix: update @vitest/eslint-plugin, i18next, and react-i18next versions for compatibility 2026-03-22 13:30:41 +00:00
GitHub Actions
441864be95 fix: add DeleteCertificateDialog component with confirmation dialog for certificate deletion
- Implement DeleteCertificateDialog component to handle certificate deletion confirmation.
- Add tests for DeleteCertificateDialog covering various scenarios including rendering, confirmation, and cancellation.
- Update translation files for multiple languages to include new strings related to certificate deletion.
- Create end-to-end tests for certificate deletion UX, including button visibility, confirmation dialog, and success/failure scenarios.
2026-03-22 13:30:41 +00:00
GitHub Actions
2c9c791ae5 fix: update package versions in package-lock.json for compatibility 2026-03-22 13:30:41 +00:00
GitHub Actions
ea3e8e8371 docs: track CVE-2026-27171 zlib CPU exhaustion as a known medium vulnerability 2026-03-22 13:30:41 +00:00
Jeremy
c5dc4a9d71 Merge pull request #872 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update dependency i18next to ^25.10.3 (feature/beta-release)
2026-03-21 21:59:28 -04:00
renovate[bot]
3b3ae29414 fix(deps): update dependency i18next to ^25.10.3 2026-03-22 01:11:06 +00:00
Jeremy
551532d41b Merge pull request #870 from Wikid82/fix/cwe-614-secure-cookie-attribute
fix(security): harden auth cookie to always set Secure attribute (CWE-614)
2026-03-21 15:14:46 -04:00
GitHub Actions
20537d7bd9 fix(e2e): add Authorization header to API calls in gaps and webkit specs 2026-03-21 16:21:58 +00:00
Jeremy
66b37b5a98 Merge branch 'development' into fix/cwe-614-secure-cookie-attribute 2026-03-21 12:18:38 -04:00
Jeremy
9d4b6e5b43 Merge pull request #871 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-21 12:17:46 -04:00
renovate[bot]
f335b3f03f fix(deps): update non-major-updates 2026-03-21 16:17:20 +00:00
GitHub Actions
52f759cc00 fix(e2e): pass Authorization header in import session cleanup helpers
- Add getStoredAuthHeader helper that reads charon_auth_token from
  localStorage and constructs an Authorization: Bearer header
- Apply the header to all page.request.* API calls in readImportStatus
  and issuePendingSessionCancel
- The previous code relied on the browser cookie jar for these cleanup
  API calls; with Secure=true on auth cookies, browsers refuse to send
  cookies over HTTP to 127.0.0.1 (IP address, not localhost hostname)
  causing silent 401s that left pending ImportSession rows in the DB
- Unreleased sessions caused all subsequent caddy-import tests to show
  the pending-session banner instead of the Caddyfile textarea, failing
  every test after the first
- The fix mirrors how the React app authenticates: via Authorization
  header, which is transport-independent and works on both HTTP and HTTPS
2026-03-21 14:21:55 +00:00
GitHub Actions
cc3cb1da4b fix(security): harden auth cookie to always set Secure attribute
- Remove the conditional secure=false branch from setSecureCookie that
  allowed cookies to be issued without the Secure flag when requests
  arrived over HTTP from localhost or RFC 1918 private addresses
- Pass the literal true to c.SetCookie directly, eliminating the
  dataflow path that triggered CodeQL go/cookie-secure-not-set (CWE-614)
- Remove the now-dead codeql suppression comment; the root cause is
  gone, not merely silenced
- Update setSecureCookie doc comment to reflect that Secure is always
  true: all major browsers (Chrome 66+, Firefox 75+, Safari 14+) honour
  the Secure attribute on localhost HTTP connections, and direct
  HTTP-on-private-IP access without TLS is an unsupported deployment
  model for Charon which is designed to sit behind Caddy TLS termination
- Update the five TestSetSecureCookie HTTP/local tests that previously
  asserted Secure=false to now assert Secure=true, reflecting the
  elimination of the insecure code path
- Add Secure=true assertion to TestClearSecureCookie to provide explicit
  coverage of the clear-cookie path
2026-03-21 13:17:45 +00:00
GitHub Actions
2c608bf684 docs: track CVE-2026-27171 zlib CPU exhaustion as a known medium vulnerability 2026-03-21 12:30:20 +00:00
Jeremy
a855ed0cf6 Merge pull request #869 from Wikid82/feature/beta-release
fix: resolve security header profile preset slugs when assigning via UUID string
2026-03-21 01:46:32 -04:00
GitHub Actions
ad7e97e7df fix: align test expectations with updated proxy host handler behavior 2026-03-21 03:05:10 +00:00
GitHub Actions
a2fea2b368 fix: update tools list in agent markdown files for consistency 2026-03-21 02:35:28 +00:00
GitHub Actions
c428a5be57 fix: propagate pipeline exit codes in CI quality-checks workflow 2026-03-21 02:23:16 +00:00
GitHub Actions
22769977e3 fix: clarify that advanced_config requires Caddy JSON, not Caddyfile syntax 2026-03-21 02:12:24 +00:00
Jeremy
50fb6659da Merge pull request #863 from Wikid82/feature/beta-release
fix(uptime): fix TCP monitor UX — correct format guidance and add client-side validation
2026-03-20 22:03:08 -04:00
GitHub Actions
e4f2606ea2 fix: resolve security header profile preset slugs when assigning via UUID string 2026-03-21 01:59:34 +00:00
GitHub Actions
af5cdf48cf fix: suppress pgproto3/v2 CVE-2026-4427 alias in vulnerability ignore files 2026-03-21 01:42:18 +00:00
GitHub Actions
1940f7f55d fix(tests): improve DOM order validation for type selector and URL input in CreateMonitorModal 2026-03-21 00:47:03 +00:00
GitHub Actions
c785c5165d fix: validate TCP format and update aria attributes in CreateMonitorModal 2026-03-21 00:47:03 +00:00
GitHub Actions
eaf981f635 fix(deps): update katex to version 0.16.40 and tldts to version 7.0.27 in package-lock.json 2026-03-21 00:47:03 +00:00
GitHub Actions
4284bcf0b6 fix(security): update known vulnerabilities section in SECURITY.md to reflect critical CVE-2025-68121 and additional high-severity issues 2026-03-21 00:47:03 +00:00
GitHub Actions
586f7cfc98 fix(security): enhance vulnerability reporting and documentation in SECURITY.md 2026-03-21 00:47:03 +00:00
GitHub Actions
15e9efeeae fix(security): add security review instructions to Management and QA Security agents 2026-03-21 00:47:03 +00:00
Jeremy
cd8bb2f501 Merge pull request #868 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-20 20:14:19 -04:00
renovate[bot]
fa42e79af3 fix(deps): update non-major-updates 2026-03-21 00:12:20 +00:00
Jeremy
859ddaef1f Merge pull request #867 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-20 14:10:06 -04:00
renovate[bot]
3b247cdd73 fix(deps): update non-major-updates 2026-03-20 18:09:46 +00:00
Jeremy
00aab022f5 Merge pull request #866 from Wikid82/renovate/feature/beta-release-knip-6.x
chore(deps): update dependency knip to v6 (feature/beta-release)
2026-03-20 14:08:29 -04:00
renovate[bot]
a40764d7da chore(deps): update dependency knip to v6 2026-03-20 12:00:39 +00:00
Jeremy
87b3db7019 Merge branch 'development' into feature/beta-release 2026-03-20 02:14:04 -04:00
Jeremy
ded533d690 Merge pull request #865 from Wikid82/renovate/feature/beta-release-nick-fields-retry-4.x
chore(deps): update nick-fields/retry action to v4 (feature/beta-release)
2026-03-20 02:13:46 -04:00
Jeremy
fc4ceafa20 Merge pull request #864 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update non-major-updates (feature/beta-release)
2026-03-20 02:13:31 -04:00
renovate[bot]
5b02eebfe5 chore(deps): update nick-fields/retry action to v4 2026-03-20 05:30:43 +00:00
renovate[bot]
338c9a3eef chore(deps): update non-major-updates 2026-03-20 05:30:39 +00:00
GitHub Actions
68d21fc20b fix: patch CVE-2026-30836 in Caddy build by pinning smallstep/certificates to v0.30.0 2026-03-20 04:15:29 +00:00
GitHub Actions
ea9ebdfdf2 fix(tools): update tools list in agent markdown files for consistency 2026-03-20 04:14:56 +00:00
GitHub Actions
1d09c793f6 fix(uptime): remove 'tcp://' prefix from Redis monitor URL in create and payload validation 2026-03-20 02:57:00 +00:00
GitHub Actions
856fd4097b fix(deps): update undici and tar to latest versions for improved stability 2026-03-20 02:47:00 +00:00
GitHub Actions
bb14ae73cc fix(uptime): fix TCP monitor UX — correct format guidance and add client-side validation
The TCP monitor creation form showed a placeholder that instructed users to enter a URL with the tcp:// scheme prefix (e.g., tcp://192.168.1.1:8080). Following this guidance caused a silent HTTP 500 error because Go's net.SplitHostPort rejects any input containing a scheme prefix, expecting bare host:port format only.

- Corrected the urlPlaceholder translation key to remove the tcp:// prefix
- Added per-type dynamic placeholder (urlPlaceholderHttp / urlPlaceholderTcp) so the URL input shows the correct example format as soon as the user selects a monitor type
- Added per-type helper text below the URL input explaining the required format, updated in real time when the type selector changes
- Added client-side validation: typing a scheme prefix (://) in TCP mode shows an inline error and blocks form submission before the request reaches the backend
- Reordered the Create Monitor form so the type selector appears before the URL input, giving users the correct format context before they type
- Type selector onChange now clears any stale urlError to prevent incorrect error messages persisting after switching from TCP back to HTTP
- Added 5 new i18n keys across all 5 supported locales (en, de, fr, es, zh)
- Added 10 RTL unit tests covering all new validation paths including the type-change error-clear scenario
- Added 9 Playwright E2E tests covering placeholder variants, helper text, inline error lifecycle, submission blocking, and successful TCP creation

Closes #issue-5 (TCP monitor UI cannot add monitor when following placeholder)
2026-03-20 01:19:43 +00:00
Jeremy
44450ff88a Merge pull request #862 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update dependency anchore/grype to v0.110.0 (feature/beta-release)
2026-03-19 19:46:25 -04:00
renovate[bot]
3a80e032f4 chore(deps): update dependency anchore/grype to v0.110.0 2026-03-19 21:09:01 +00:00
Jeremy
6e2d89372f Merge pull request #859 from Wikid82/feature/beta-release
fix(frontend): stabilize CrowdSec first-enable UX and guard empty-value regression
2026-03-19 16:56:50 -04:00
GitHub Actions
5bf7b54496 chore: proactively pin grpc and goxmldsig in Docker builder stages to patch embedded binary CVEs 2026-03-19 18:18:28 +00:00
GitHub Actions
0bdcb2a091 chore: suppress third-party binary CVEs with documented justification and expiry dates 2026-03-19 18:18:28 +00:00
GitHub Actions
b988179685 fix: update @emnapi/core, @emnapi/runtime, baseline-browser-mapping, and i18next to latest versions for improved stability 2026-03-19 18:18:28 +00:00
GitHub Actions
cbfe80809e fix: update @emnapi/core, @emnapi/runtime, and katex to latest versions for improved stability 2026-03-19 18:18:28 +00:00
GitHub Actions
9f826f764c fix: update dependencies in go.work.sum for improved compatibility and performance 2026-03-19 18:18:28 +00:00
Jeremy
262a805317 Merge pull request #861 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-19 14:15:42 -04:00
renovate[bot]
ec25165e54 fix(deps): update non-major-updates 2026-03-19 18:02:03 +00:00
GitHub Actions
7b34e2ecea fix: update google.golang.org/grpc to version 1.79.3 for improved compatibility 2026-03-19 13:10:18 +00:00
GitHub Actions
ec9b8ac925 fix: update @types/debug to version 4.1.13 for improved stability 2026-03-19 12:59:23 +00:00
GitHub Actions
431d88c47c fix: update @tanstack/query-core, @tanstack/react-query, @types/debug, eslint-plugin-testing-library, i18next, and knip to latest versions for improved stability and performance 2026-03-19 12:58:46 +00:00
GitHub Actions
e08e1861d6 fix: update @oxc-project and @rolldown packages to version 1.0.0-rc.10 for improved compatibility 2026-03-19 05:17:14 +00:00
GitHub Actions
64d2d4d423 fix: update ts-api-utils to version 2.5.0 for improved functionality 2026-03-19 05:16:32 +00:00
Jeremy
9f233a0128 Merge pull request #860 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update non-major-updates (feature/beta-release)
2026-03-18 20:30:26 -04:00
renovate[bot]
6939c792bd chore(deps): update non-major-updates 2026-03-18 23:07:56 +00:00
GitHub Actions
853940b74a fix: update mockResolvedValue calls for getSecurityStatus to improve test clarity 2026-03-18 23:06:24 +00:00
GitHub Actions
5aa8940af2 fix: update tools list in agent markdown files for consistency and clarity 2026-03-18 23:04:52 +00:00
GitHub Actions
cd3f2a90b4 fix: seed lapi-status in renderWithSeed to prevent loading gaps 2026-03-18 22:19:22 +00:00
GitHub Actions
bf89c2603d fix: enhance invite token validation for hex format and case sensitivity 2026-03-18 22:15:39 +00:00
GitHub Actions
19b388d865 fix: update Caddy security version to 1.1.50 in Dockerfile 2026-03-18 22:11:50 +00:00
GitHub Actions
25e40f164d fix: replace userEvent.click with user.click for consistency in CrowdSec tests 2026-03-18 22:08:05 +00:00
GitHub Actions
5505f66c41 fix: clarify comments on optimistic updates and server state handling in Security component 2026-03-18 22:06:40 +00:00
GitHub Actions
9a07619b89 fix: assert cloud-metadata error and no raw IPv6 leak for mapped metadata IP 2026-03-18 19:08:55 +00:00
GitHub Actions
faf2041a82 fix: sanitize IPv4-mapped IPv6 address in SSRF error message 2026-03-18 19:06:31 +00:00
GitHub Actions
460834f8f3 fix: use correct checkbox assertion for CrowdSec toggle test 2026-03-18 19:05:16 +00:00
GitHub Actions
75ae77a6bf fix: assert all db.Create calls in uptime service tests 2026-03-18 19:03:53 +00:00
GitHub Actions
73f2134caf fix(tests): improve server readiness check in UptimeService test to prevent misleading failures 2026-03-18 18:45:59 +00:00
GitHub Actions
c5efc30f43 fix: eliminate bcrypt DefaultCost from test setup to prevent CI flakiness 2026-03-18 18:13:18 +00:00
GitHub Actions
3099d74b28 fix: ensure cloud metadata SSRF error is consistent for IPv4-mapped addresses 2026-03-18 17:23:53 +00:00
GitHub Actions
fcc9309f2e chore(deps): update indirect dependencies for improved compatibility and performance 2026-03-18 17:12:01 +00:00
Jeremy
e581a9e7e7 Merge branch 'development' into feature/beta-release 2026-03-18 13:11:50 -04:00
Jeremy
ac72e6c3ac Merge pull request #858 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-18 13:11:20 -04:00
renovate[bot]
db824152ef fix(deps): update non-major-updates 2026-03-18 17:00:26 +00:00
GitHub Actions
1de29fe6fc fix(frontend): stabilize CrowdSec first-enable UX and guard empty-value regression
When CrowdSec is first enabled, the 10-60 second startup window caused
the toggle to immediately flicker back to unchecked, the card badge to
show 'Disabled' throughout startup, CrowdSecKeyWarning to flash before
bouncer registration completed, and CrowdSecConfig to show alarming
LAPI-not-ready banners to the user.

Root cause: the toggle, badge, and warning conditions all read from
stale sources (crowdsecStatus local state and status.crowdsec.enabled
server data) which neither reflects user intent during a pending mutation.

- Derive crowdsecChecked from crowdsecPowerMutation.variables during
  the pending window so the UI reflects intent immediately on click,
  not the lagging server state
- Show a 'Starting...' badge in warning variant throughout the startup
  window so the user knows the operation is in progress
- Suppress CrowdSecKeyWarning unconditionally while the mutation is
  pending, preventing the bouncer key alert from flashing before
  registration completes on the backend
- Broadcast the mutation's running state to the QueryClient cache via
  a synthetic crowdsec-starting key so CrowdSecConfig.tsx can read it
  without prop drilling
- In CrowdSecConfig, suppress the LAPI 'not running' (red) and
  'initializing' (yellow) banners while the startup broadcast is active,
  with a 90-second safety cap to prevent stale state from persisting
  if the tab is closed mid-mutation
- Add security.crowdsec.starting translation key to all five locales
- Add two backend regression tests confirming that empty-string setting
  values are accepted (not rejected by binding validation), preventing
  silent re-introduction of the Issue 4 bug
- Add nine RTL tests covering toggle stabilization, badge text, warning
  suppression, and LAPI banner suppression/expiry
- Add four Playwright E2E tests using route interception to simulate
  the startup delay in a real browser context

Fixes Issues 3 and 4 from the fresh-install bug report.
2026-03-18 16:57:23 +00:00
GitHub Actions
ac2026159e chore: update tailwindcss to version 4.2.2 in package.json 2026-03-18 16:46:50 +00:00
GitHub Actions
cfb28055cf fix: add vulnerability suppressions for CVE-2026-2673 in libcrypto3 and libssl3 with justification and review timeline 2026-03-18 11:08:58 +00:00
GitHub Actions
a2d8970b22 chore: Refactor agent tools for improved organization and efficiency across documentation, frontend development, planning, Playwright testing, QA security, and supervisor roles. 2026-03-18 10:36:14 +00:00
GitHub Actions
abadf9878a chore(deps): update electron-to-chromium to version 1.5.321 2026-03-18 10:27:06 +00:00
GitHub Actions
87590ac4e8 fix: simplify error handling and improve readability in URL validation and uptime service tests 2026-03-18 10:25:25 +00:00
Jeremy
999a81dce7 Merge pull request #857 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update dependency knip to ^5.88.0 (feature/beta-release)
2026-03-18 06:24:40 -04:00
Jeremy
031457406a Merge pull request #855 from Wikid82/feature/beta-release
fix(uptime): allow RFC 1918 IPs for admin-configured monitors
2026-03-18 06:09:51 -04:00
renovate[bot]
3d9d183b77 chore(deps): update dependency knip to ^5.88.0 2026-03-18 10:07:26 +00:00
GitHub Actions
379c664b5c fix(test): align cloud-metadata SSRF handler test with updated error message
The settings handler SSRF test table expected the generic "private ip"
error string for the cloud-metadata case (169.254.169.254). After the
url_validator was updated to return a distinct "cloud metadata" error for
that address, the handler test's errorContains check failed on every CI run.

Updated the test case expectation from "private" to "cloud metadata" to
match the more precise error message now produced by the validator.
2026-03-18 03:38:29 +00:00
GitHub Actions
4d8f09e279 fix: improve readiness checks and error handling in uptime service tests 2026-03-18 03:22:32 +00:00
GitHub Actions
8a0e91ac3b chore: strengthen AllowRFC1918 permit tests to assert success and URL correctness 2026-03-18 03:22:32 +00:00
GitHub Actions
3bc798bc9d fix: normalize IPv4-mapped cloud-metadata address to its IPv4 form before error reporting
- IPv4-mapped cloud metadata (::ffff:169.254.169.254) previously fell through
  the IPv4-mapped IPv6 detection block and returned the generic private-IP error
  instead of the cloud-metadata error, making the two cases inconsistent
- The IPv4-mapped error path used ip.String() (the raw ::ffff:… form) directly
  rather than sanitizeIPForError, potentially leaking the unsanitized IPv6
  address in error messages visible to callers
- Now extracts the IPv4 from the mapped address before both the cloud-metadata
  comparison and the sanitization call, so ::ffff:169.254.169.254 produces the
  same "access to cloud metadata endpoints is blocked" error as 169.254.169.254
  and the error message is always sanitized through the shared helper
- Updated the corresponding test to assert the cloud-metadata message and the
  absence of the raw IPv6 representation in the error text
2026-03-18 03:22:32 +00:00
GitHub Actions
8b4e0afd43 fix: format SeedDefaultSecurityConfig for improved readability 2026-03-18 03:22:32 +00:00
GitHub Actions
c7c4fc8915 fix(deps): update flatted to version 3.4.2 for improved stability 2026-03-18 03:22:32 +00:00
Jeremy
41c0252cf1 Merge pull request #856 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update module github.com/greenpau/caddy-security to v1.1.49 (feature/beta-release)
2026-03-17 23:15:17 -04:00
renovate[bot]
4c375ad86f chore(deps): update module github.com/greenpau/caddy-security to v1.1.49 2026-03-18 02:33:53 +00:00
Jeremy
459a8fef42 Merge branch 'development' into feature/beta-release 2026-03-17 22:32:24 -04:00
GitHub Actions
00a18704e8 fix(uptime): allow RFC 1918 IPs for admin-configured monitors
HTTP/HTTPS uptime monitors targeting LAN addresses (192.168.x.x,
10.x.x.x, 172.16.x.x) permanently reported 'down' on fresh installs
because SSRF protection rejects RFC 1918 ranges at two independent
checkpoints: the URL validator (DNS-resolution layer) and the safe
dialer (TCP-connect layer). Fixing only one layer leaves the monitor
broken in practice.

- Add IsRFC1918() predicate to the network package covering only the
  three RFC 1918 CIDRs; 169.254.x.x (link-local / cloud metadata)
  and loopback are intentionally excluded
- Add WithAllowRFC1918() functional option to both SafeHTTPClient and
  ValidationConfig; option defaults to false so existing behaviour is
  unchanged for every call site except uptime monitors
- In uptime_service.go, pass WithAllowRFC1918() to both
  ValidateExternalURL and NewSafeHTTPClient together; a coordinating
  comment documents that both layers must be relaxed as a unit
- 169.254.169.254 and the full 169.254.0.0/16 link-local range remain
  unconditionally blocked; the cloud-metadata error path is preserved
- 21 new tests across three packages, including an explicit regression
  guard that confirms RFC 1918 blocks are still applied without the
  option set (TestValidateExternalURL_RFC1918BlockedByDefault)

Fixes issues 6 and 7 from the fresh-install bug report.
2026-03-17 21:22:56 +00:00
Jeremy
dc9bbacc27 Merge pull request #854 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update release-drafter/release-drafter digest to 44a942e (feature/beta-release)
2026-03-17 16:41:13 -04:00
Jeremy
4da4e1a0d4 Merge branch 'feature/beta-release' into renovate/feature/beta-release-non-major-updates 2026-03-17 14:37:17 -04:00
Jeremy
3318b4af80 Merge pull request #852 from Wikid82/feature/beta-release
feat(security): seed default SecurityConfig row on application startup
2026-03-17 14:36:45 -04:00
GitHub Actions
c1aaa48ecb chore: cover error path in SeedDefaultSecurityConfig and letsencrypt cert cleanup loop
- The DB error return branch in SeedDefaultSecurityConfig was never
  exercised because all seed tests only ran against a healthy in-memory
  database; added a test that closes the underlying connection before
  calling the function so the FirstOrCreate error path is reached
- The letsencrypt certificate cleanup loop in Register was unreachable
  in all existing tests because no test pre-seeded a ProxyHost with
  an letsencrypt cert association; added a test that creates that
  precondition so the log and Update lines inside the loop execute
- These were the last two files blocking patch coverage on PR #852
2026-03-17 17:45:39 +00:00
renovate[bot]
f82a892405 chore(deps): update release-drafter/release-drafter digest to 44a942e 2026-03-17 17:17:04 +00:00
GitHub Actions
287e85d232 fix(ci): quote shell variables to prevent word splitting in integration test
- All unquoted $i loop counter comparisons and ${TMP_COOKIE} curl
  option arguments in the rate limit integration script were flagged
  by shellcheck SC2086
- Unquoted variables in [ ] test expressions and curl -b/-c options
  can cause subtle failures if the value ever contains whitespace or
  glob characters, and are a shellcheck hard warning that blocks CI
  linting gates
- Quoted all affected variables in place with no logic changes
2026-03-17 17:15:19 +00:00
Jeremy
fa6fbc8ce9 Merge pull request #853 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update paulhatch/semantic-version action to v6.0.2 (feature/beta-release)
2026-03-17 13:14:55 -04:00
GitHub Actions
61418fa9dd fix(security): persist RateLimitMode in Upsert and harden integration test payload
- The security config Upsert update path copied all rate limit fields
  from the incoming request onto the existing database record except
  RateLimitMode, so the seeded default value of "disabled" always
  survived a POST regardless of what the caller sent
- This silently prevented the Caddy rate_limit handler from being
  injected on any container with a pre-existing config record (i.e.,
  every real deployment and every CI run after migration)
- Added the missing field assignment so RateLimitMode is correctly
  persisted on update alongside all other rate limit settings
- Integration test payload now also sends rate_limit_enable alongside
  rate_limit_mode so the handler sync logic fires via its explicit
  first branch, providing belt-and-suspenders correctness independent
  of which path the caller uses to express intent
2026-03-17 17:06:02 +00:00
GitHub Actions
0df1126aa9 fix(deps): update modernc.org/sqlite to version 1.47.0 for improved functionality 2026-03-17 14:31:42 +00:00
renovate[bot]
1c72469ad6 chore(deps): update paulhatch/semantic-version action to v6.0.2 2026-03-17 14:30:44 +00:00
GitHub Actions
338f864f60 fix(ci): set correct rate_limit_mode field in integration test security config
- The rate-limit integration test was sending rate_limit_enable:true in the
  security config POST, but the backend injects the Caddy rate_limit handler
  only when rate_limit_mode is the string "enabled"
- Because rate_limit_mode was absent from the payload, the database default
  of "disabled" persisted and the guard condition always evaluated false,
  leaving the handler uninjected across all 10 verify attempts
- Replaced the boolean rate_limit_enable with the string field
  rate_limit_mode:"enabled" to match the exact contract the backend enforces
2026-03-17 14:29:35 +00:00
GitHub Actions
8b0011f6c6 fix(ci): enhance rate limit integration test reliability
- Added HTTP status checks for login and security config POST requests to ensure proper error handling.
- Implemented a readiness gate for the Caddy admin API before applying security configurations.
- Increased sleep duration before verifying rate limit handler to accommodate Caddy's configuration propagation.
- Changed verification failure from a warning to a hard exit to prevent misleading test results.
- Updated Caddy admin API URL to use the canonical trailing slash in multiple locations.
- Adjusted retry parameters for rate limit verification to reduce polling noise.
- Removed stale GeoIP checksum validation from the Dockerfile's non-CI path to simplify the build process.
2026-03-17 14:05:25 +00:00
GitHub Actions
e6a044c532 fix(deps): update caniuse-lite to version 1.0.30001780 for improved compatibility 2026-03-17 12:40:55 +00:00
GitHub Actions
bb1e59ea93 fix(deps): update bytedance/gopkg to version 0.1.4 for improved functionality 2026-03-17 12:38:43 +00:00
GitHub Actions
b761d7d4f7 feat(security): seed default SecurityConfig row on application startup
On a fresh install the security_configs table is auto-migrated but
contains no rows. Any code path reading SecurityConfig by name received
an empty Go struct with zero values, producing an all-disabled UI state
that offered no guidance to the user and made the security status
endpoint appear broken.

Adds a SeedDefaultSecurityConfig function that uses FirstOrCreate to
guarantee a default row exists with safe, disabled-by-default values on
every startup. The call is idempotent — existing rows are never modified,
so upgrades are unaffected. If the seed fails the application logs a
warning and continues rather than crashing.

Zero-valued rate-limit fields are intentional and safe: the Cerberus
rate-limit middleware applies hardcoded fallback thresholds when the
stored values are zero, so enabling rate limiting without configuring
thresholds results in sensible defaults rather than a divide-by-zero or
traffic block.

Adds three unit tests covering the empty-database, idempotent, and
do-not-overwrite-existing paths.
2026-03-17 12:33:40 +00:00
Jeremy
418fb7d17c Merge pull request #851 from Wikid82/feature/beta-release
fix(settings): allow empty string as a valid setting value
2026-03-16 23:24:37 -04:00
Jeremy
5084483984 Merge branch 'development' into feature/beta-release 2026-03-16 22:05:55 -04:00
GitHub Actions
3c96810aa1 fix(deps): update @babel/helpers, @babel/parser, @babel/runtime, and enhanced-resolve to latest versions for improved stability 2026-03-17 02:05:00 +00:00
GitHub Actions
dcd1ec7e95 fix: improve error handling in TestSettingsHandler_UpdateSetting_EmptyValueAccepted 2026-03-17 02:01:48 +00:00
GitHub Actions
4f222b6308 fix: make 'value' field optional in UpdateSettingRequest struct 2026-03-17 01:40:35 +00:00
Jeremy
071ae38d35 Merge pull request #850 from Wikid82/feature/beta-release
Feature: Pushover Notification Provider
2026-03-16 20:09:08 -04:00
GitHub Actions
3385800f41 fix(deps): update core-js-compat to version 3.49.0 for improved compatibility 2026-03-16 21:48:19 +00:00
GitHub Actions
4fe538b37e chore: add unit tests for Slack and Pushover service flags, and validate Pushover dispatch behavior 2026-03-16 21:38:40 +00:00
Jeremy
2bdf4f8286 Merge branch 'development' into feature/beta-release 2026-03-16 14:26:07 -04:00
Jeremy
a96366957e Merge pull request #849 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update non-major-updates (feature/beta-release)
2026-03-16 14:24:11 -04:00
renovate[bot]
c44642241c chore(deps): update non-major-updates 2026-03-16 18:22:12 +00:00
GitHub Actions
b5bf505ab9 fix: update go-sqlite3 to version 1.14.37 and modernc.org/sqlite to version 1.46.2 for improved stability 2026-03-16 18:20:35 +00:00
GitHub Actions
51f59e5972 fix: update @typescript-eslint packages to version 8.57.1 for improved compatibility and stability 2026-03-16 18:19:36 +00:00
GitHub Actions
65d02e754e feat: add support for Pushover notification provider
- Updated the list of supported notification provider types to include 'pushover'.
- Enhanced the notifications API tests to validate Pushover integration.
- Modified the notifications form to include fields specific to Pushover, such as API Token and User Key.
- Implemented CRUD operations for Pushover providers in the settings.
- Added end-to-end tests for Pushover provider functionality, including form rendering, payload validation, and security checks.
- Updated translations to include Pushover-specific labels and placeholders.
2026-03-16 18:16:14 +00:00
Jeremy
816c0595e1 Merge pull request #834 from Wikid82/feature/beta-release
Feature: Slack Notification Provider
2026-03-16 11:15:29 -04:00
GitHub Actions
9496001811 fix: update undici to version 7.24.4 for improved stability and security 2026-03-16 12:33:58 +00:00
Jeremy
ec1b79c2b7 Merge branch 'development' into feature/beta-release 2026-03-16 08:30:45 -04:00
Jeremy
bab79f2349 Merge pull request #846 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update non-major-updates (feature/beta-release)
2026-03-16 08:28:36 -04:00
renovate[bot]
edd7405313 chore(deps): update non-major-updates 2026-03-16 12:28:25 +00:00
GitHub Actions
79800871fa fix: harden frontend-builder with npm upgrade to mitigate bundled CVEs 2026-03-16 12:26:55 +00:00
Jeremy
67dd87d3a9 Merge pull request #845 from Wikid82/main
Propagate changes from main into development
2026-03-16 08:24:38 -04:00
Jeremy
dfc2beb8f3 Merge pull request #844 from Wikid82/nightly
Weekly: Promote nightly to main (2026-03-16)
2026-03-16 08:16:42 -04:00
GitHub Actions
5e5eae7422 fix: ensure Semgrep hook triggers on Dockerfile-only commits 2026-03-16 11:44:27 +00:00
GitHub Actions
78f216eaef fix: enhance payload handling in Slack provider creation to track token presence 2026-03-16 11:41:06 +00:00
Jeremy
34d5cca972 Merge branch 'main' into nightly 2026-03-16 07:35:56 -04:00
Jeremy
5d771381a1 Merge pull request #842 from Wikid82/bot/update-geolite2-checksum
chore(docker): update GeoLite2-Country.mmdb checksum
2026-03-16 07:35:38 -04:00
GitHub Actions
95a65069c0 fix: handle existing PR outputs in promotion job 2026-03-16 11:17:37 +00:00
Jeremy
1e4b2d1d03 Merge pull request #843 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-16 07:15:40 -04:00
renovate[bot]
81f1dce887 fix(deps): update non-major-updates 2026-03-16 11:06:23 +00:00
Wikid82
3570c05805 chore(docker): update GeoLite2-Country.mmdb checksum
Automated checksum update for GeoLite2-Country.mmdb database.

Old: b79afc28a0a52f89c15e8d92b05c173f314dd4f687719f96cf921012d900fcce
New: aa154fc6bcd712644de232a4abcdd07dac1f801308c0b6f93dbc2b375443da7b

Auto-generated by: .github/workflows/update-geolite2.yml
2026-03-16 02:58:27 +00:00
GitHub Actions
b66cc34e1c fix: update Caddy security version to 1.1.48 in Dockerfile 2026-03-15 20:49:53 +00:00
GitHub Actions
5bafd92edf fix: supply slack webhook token in handler create sub-tests
The slack sub-tests in TestDiscordOnly_CreateRejectsNonDiscord and
TestBlocker3_CreateProviderRejectsNonDiscordWithSecurityEvents were
omitting the required token field from their request payloads.
CreateProvider enforces that Slack providers must have a non-empty
token (the webhook URL) at creation time. Without it the service
returns "slack webhook URL is required", which the handler does not
classify as a 400 validation error, so it falls through to 500.

Add a token field to each test struct, populate it for the slack
case with a valid-format Slack webhook URL, and use
WithSlackURLValidator to bypass the real format check in unit tests —
matching the pattern used in all existing service-level Slack tests.
2026-03-15 15:17:23 +00:00
GitHub Actions
6e4294dce1 fix: validate Slack webhook URL at provider create/update time 2026-03-15 12:23:27 +00:00
GitHub Actions
82b1c85b7c fix: clarify feature flag behavior for Slack notifications in documentation 2026-03-15 12:14:48 +00:00
GitHub Actions
41ecb7122f fix: update baseline-browser-mapping and caniuse-lite to latest versions 2026-03-15 11:58:48 +00:00
GitHub Actions
2fa7608b9b fix: guard routeBodyPromise against indefinite hang in security test 2026-03-15 11:51:16 +00:00
GitHub Actions
285ee2cdda fix: expand Semgrep ruleset to cover TypeScript, Dockerfile, and shell security 2026-03-15 11:45:18 +00:00
GitHub Actions
72598ed2ce fix: inject Slack URL validator via constructor option instead of field mutation 2026-03-15 11:27:51 +00:00
GitHub Actions
8670cdfd2b fix: format notification services table for better readability 2026-03-15 11:17:34 +00:00
GitHub Actions
f8e8440388 fix: correct GeoIP CI detection to require truthy value 2026-03-15 11:15:56 +00:00
GitHub Actions
ab4dee5fcd fix: make Slack webhook URL validator injectable on NotificationService 2026-03-15 11:15:10 +00:00
Jeremy
04e87e87d5 Merge pull request #841 from Wikid82/renovate/feature/beta-release-jsdom-29.x
chore(deps): update dependency jsdom to v29 (feature/beta-release)
2026-03-15 07:00:19 -04:00
Jeremy
cc96435db1 Merge pull request #840 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update softprops/action-gh-release digest to b25b93d (feature/beta-release)
2026-03-15 06:59:51 -04:00
renovate[bot]
53af0a6866 chore(deps): update dependency jsdom to v29 2026-03-15 10:56:03 +00:00
renovate[bot]
3577ce6c56 chore(deps): update softprops/action-gh-release digest to b25b93d 2026-03-15 10:55:54 +00:00
Jeremy
0ce35f2d64 Merge branch 'development' into feature/beta-release 2026-03-14 23:47:43 -04:00
Jeremy
0e556433f7 Merge pull request #839 from Wikid82/hotfix/login
Hotfix: Login / Auth on Private IP
2026-03-14 23:45:41 -04:00
GitHub Actions
4b170b69e0 fix: update Caddy security version to 1.1.47 in Dockerfile 2026-03-15 03:25:41 +00:00
GitHub Actions
fd58f9d99a fix(auth): update SameSite cookie policy description for clarity 2026-03-15 03:23:06 +00:00
GitHub Actions
f33ab83b7c fix(auth): rename isLocalHost to isLocalOrPrivateHost and update related tests 2026-03-15 03:20:11 +00:00
GitHub Actions
6777f6e8ff feat(auth): implement Bearer token fallback in fetchSessionUser for private network HTTP connections
- Expanded fetchSessionUser to include Bearer token from localStorage as a fallback for authentication when Secure cookies fail.
- Updated headers to conditionally include Authorization if a token is present.
- Ensured compatibility with the recent fix for the Secure cookie flag on private network connections.
2026-03-15 02:25:07 +00:00
GitHub Actions
1096b00b94 fix: set PORT environment variable for httpbin backend in integration scripts 2026-03-14 16:44:35 +00:00
GitHub Actions
6180d53a93 fix: update undici to version 7.24.2 in package-lock.json 2026-03-14 16:44:35 +00:00
Jeremy
fca1139c81 Merge pull request #838 from Wikid82/renovate/feature/beta-release-release-drafter-release-drafter-7.x
chore(deps): update release-drafter/release-drafter action to v7 (feature/beta-release)
2026-03-14 12:30:46 -04:00
Jeremy
847b10322a Merge pull request #837 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update non-major-updates (feature/beta-release)
2026-03-14 12:30:29 -04:00
Jeremy
59251c8f27 Merge branch 'feature/beta-release' into renovate/feature/beta-release-non-major-updates 2026-03-14 12:30:02 -04:00
GitHub Actions
58b087bc63 fix: replace curl with wget for backend readiness checks in integration scripts 2026-03-14 13:17:06 +00:00
renovate[bot]
8ab926dc8b chore(deps): update release-drafter/release-drafter action to v7 2026-03-14 13:16:45 +00:00
renovate[bot]
85f258d9f6 chore(deps): update non-major-updates 2026-03-14 13:15:37 +00:00
GitHub Actions
042c5ec6e5 fix(ci): replace abandoned httpbin image with maintained Go alternative 2026-03-13 22:44:19 +00:00
GitHub Actions
05d19c0471 fix: update lru-cache and other dependencies to latest versions 2026-03-13 20:07:30 +00:00
GitHub Actions
48af524313 chore(security): expand Semgrep coverage to include frontend and secrets scanning 2026-03-13 20:07:30 +00:00
GitHub Actions
bad97102e1 fix: repair GeoIP CI detection and harden httpbin startup in integration tests 2026-03-13 20:07:30 +00:00
GitHub Actions
98a4efcd82 fix: handle errors gracefully when commenting on PRs in supply chain verification workflow 2026-03-13 20:07:30 +00:00
Jeremy
f631dfc628 Merge pull request #836 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update non-major-updates (feature/beta-release)
2026-03-13 15:58:41 -04:00
renovate[bot]
eb5b74cbe3 chore(deps): update non-major-updates 2026-03-13 19:08:11 +00:00
GitHub Actions
1785ccc39f fix: remove zlib vulnerability suppression and update review dates for Nebula ECDSA signature malleability 2026-03-13 14:14:22 +00:00
GitHub Actions
4b896c2e3c fix: replace curl with wget for healthcheck commands in Docker configurations 2026-03-13 14:13:37 +00:00
GitHub Actions
88a9cdb0ff fix(deps): update @vitejs/plugin-react to version 6.0.1 and adjust peer dependency for @rolldown/plugin-babel 2026-03-13 12:33:00 +00:00
GitHub Actions
354ff0068a fix: upgrade zlib package in Dockerfile to ensure latest security patches 2026-03-13 12:10:38 +00:00
GitHub Actions
0c419d8f85 chore: add Slack provider validation tests for payload and webhook URL 2026-03-13 12:09:35 +00:00
GitHub Actions
26be592f4d feat: add Slack notification provider support
- Updated the notification provider types to include 'slack'.
- Modified API tests to handle 'slack' as a valid provider type.
- Enhanced frontend forms to display Slack-specific fields (webhook URL and channel name).
- Implemented CRUD operations for Slack providers, ensuring proper payload structure.
- Added E2E tests for Slack notification provider, covering form rendering, validation, and security checks.
- Updated translations to include Slack-related text.
- Ensured that sensitive information (like tokens) is not exposed in API responses.
2026-03-13 03:40:02 +00:00
GitHub Actions
fb9b6cae76 fix(deps): update caddy-security version to 1.1.46 2026-03-13 01:37:09 +00:00
Jeremy
5bb9b2a6fb Merge branch 'development' into feature/beta-release 2026-03-12 13:52:54 -04:00
GitHub Actions
593694a4b4 fix(deps): update goccy/go-json to version 0.10.6 2026-03-12 17:49:05 +00:00
GitHub Actions
b207993299 fix(deps): update baseline-browser-mapping to version 2.10.7 and undici to version 7.23.0 2026-03-12 17:48:14 +00:00
Jeremy
a807288052 Merge pull request #833 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update non-major-updates (feature/beta-release)
2026-03-12 13:45:33 -04:00
renovate[bot]
49b956f916 chore(deps): update non-major-updates 2026-03-12 17:38:44 +00:00
GitHub Actions
53227de55c chore: Refactor code structure for improved readability and maintainability 2026-03-12 10:10:25 +00:00
GitHub Actions
58921556a1 fix(deps): update golang.org/x/term to version 0.41.0 2026-03-12 10:06:34 +00:00
GitHub Actions
442164cc5c fix(deps): update golang.org/x/crypto and golang.org/x/net dependencies to latest versions 2026-03-12 10:05:51 +00:00
Jeremy
8414004d8f Merge pull request #832 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-12 05:53:18 -04:00
renovate[bot]
7932188dae fix(deps): update non-major-updates 2026-03-12 09:30:08 +00:00
GitHub Actions
d4081d954f chore: update dependencies and configuration for Vite and Vitest
- Bump versions of @vitejs/plugin-react, @vitest/coverage-istanbul, @vitest/coverage-v8, and @vitest/ui to their beta releases.
- Upgrade Vite and Vitest to their respective beta versions.
- Adjust Vite configuration to disable code splitting for improved React initialization stability.
2026-03-12 04:31:31 +00:00
GitHub Actions
2e85a341c8 chore: upgrade ESLint and related plugins to version 10.x
- Updated @eslint/js and eslint to version 10.0.0 in package.json.
- Adjusted overrides for eslint-plugin-react-hooks, eslint-plugin-jsx-a11y, and eslint-plugin-promise to ensure compatibility with ESLint v10.
- Modified lefthook.yml to reflect the upgrade and noted the need for plugin support for ESLint v10.
2026-03-12 00:00:01 +00:00
GitHub Actions
2969eb58e4 chore: update TypeScript to 6.0.1-rc and adjust package dependencies
- Removed duplicate @typescript-eslint/utils dependency in frontend/package.json
- Updated TypeScript version from 5.9.3 to 6.0.1-rc in frontend/package.json and package.json
- Adjusted ResizeObserver mock to use globalThis in tests
- Modified tsconfig.json and tsconfig.node.json to include empty types array
- Cleaned up package-lock.json to reflect TypeScript version change and updated dev dependencies
2026-03-11 22:19:35 +00:00
Jeremy
9d6ecd8f73 Merge pull request #824 from Wikid82/feature/beta-release
Feature: Telegram Notification Provider
2026-03-11 14:05:55 -04:00
Jeremy
0c2a9d0ee8 Merge pull request #830 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update non-major-updates (feature/beta-release)
2026-03-11 13:20:47 -04:00
GitHub Actions
c71e6fef30 fix: improve response handling in Telegram notification provider tests to prevent race conditions 2026-03-11 16:54:54 +00:00
renovate[bot]
3186676f94 chore(deps): update non-major-updates 2026-03-11 16:26:55 +00:00
GitHub Actions
b108f11bb4 fix: update zod-validation-error dependency to version 5.0.0 2026-03-11 15:58:43 +00:00
GitHub Actions
d56e8a0f7f fix: update zod dependency version and remove outdated references in package-lock.json 2026-03-11 15:56:33 +00:00
GitHub Actions
b76c1d7efc chore: update golang.org/x/sync dependency to v0.20.0 and remove outdated golang.org/x/text v0.34.0 2026-03-11 15:54:36 +00:00
GitHub Actions
cbb2f42a2b fix: correct syntax error in bulk delete test for ProxyHosts 2026-03-11 15:53:24 +00:00
GitHub Actions
fd056c05a7 feat: Enhance Notifications feature with accessibility improvements and test remediation
- Added aria-label attributes to buttons in Notifications component for better accessibility.
- Updated Notifications tests to use new button interactions and ensure proper functionality.
- Refactored notifications payload tests to mock API responses and validate payload transformations.
- Improved error handling and feedback in notification provider tests.
- Adjusted Telegram notification provider tests to streamline edit interactions.
2026-03-11 15:33:53 +00:00
GitHub Actions
2f76b4eadc fix: update team roster formatting for consistency in Management agent 2026-03-11 15:33:53 +00:00
GitHub Actions
fde59a94ae chore: remove outdated structured autonomy commands and documentation
- Deleted sa-generate.md, sa-implement.md, and sa-plan.md as they are no longer needed.
- Removed security scan commands for CodeQL, Docker image, Go vulnerabilities, GORM, and Trivy due to redundancy.
- Eliminated SQL code review and optimization commands to streamline processes.
- Removed supply chain remediation command as it is now integrated elsewhere.
- Deleted test commands for backend and frontend coverage and unit tests to simplify testing workflow.
- Updated settings.json and CLAUDE.md to reflect the removal of commands and ensure consistency in documentation.
2026-03-11 15:33:53 +00:00
Jeremy
7409862140 Merge pull request #828 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-11 10:57:07 -04:00
renovate[bot]
065ac87815 fix(deps): update non-major-updates 2026-03-11 14:53:49 +00:00
Jeremy
d6d810f1a2 Merge pull request #827 from Wikid82/renovate/feature/beta-release-major-7-react-monorepo
chore(deps): update dependency eslint-plugin-react-hooks to v7 (feature/beta-release)
2026-03-10 22:32:06 -04:00
Jeremy
05c71988c0 Merge pull request #826 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update non-major-updates (feature/beta-release)
2026-03-10 22:31:28 -04:00
GitHub Actions
3e32610ea1 chore: Refactor tests to use findBy queries for better async handling, update mock implementations, and clean up imports across various test files. Adjust toast utility to use for-of loops for callback execution. Update Vite and Vitest configuration files for consistency. 2026-03-11 02:24:28 +00:00
renovate[bot]
be502b7533 chore(deps): update dependency eslint-plugin-react-hooks to v7 2026-03-11 02:15:03 +00:00
renovate[bot]
4e81a982aa chore(deps): update non-major-updates 2026-03-11 02:14:55 +00:00
GitHub Actions
c977c6f9a4 fit(notification): enhance Telegram integration with dynamic API base URL and improved payload validation 2026-03-11 00:34:39 +00:00
GitHub Actions
7416229ba3 fix: restore @types/eslint-plugin-jsx-a11y in devDependencies and remove from dependencies 2026-03-10 23:51:52 +00:00
GitHub Actions
9000c1f4ba chore: add comprehensive tests for Telegram notification service functionality 2026-03-10 23:32:29 +00:00
GitHub Actions
7423e64bc5 fix(dependencies): replace eslint-plugin-vitest with @vitest/eslint-plugin in configuration files 2026-03-10 23:30:08 +00:00
Jeremy
1d5f46980d Merge branch 'development' into feature/beta-release 2026-03-10 14:32:20 -04:00
Jeremy
e09efa42a8 Merge pull request #821 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update non-major-updates (feature/beta-release)
2026-03-10 14:30:09 -04:00
Jeremy
e99be20bae Merge branch 'feature/beta-release' into renovate/feature/beta-release-non-major-updates 2026-03-10 14:29:54 -04:00
GitHub Actions
6ce858e52e fix(dependencies): update ESLint and TypeScript-related packages for compatibility 2026-03-10 18:28:20 +00:00
GitHub Actions
f41bd485e3 fix(docker): update Caddy security version to 1.1.45 2026-03-10 18:20:28 +00:00
GitHub Actions
2fc5b10d3d fix(notifications): surface provider API error details in test failure messages 2026-03-10 17:30:31 +00:00
GitHub Actions
f3d69b0116 feat: add validation to prevent testing new notification providers without saving 2026-03-10 13:23:13 +00:00
renovate[bot]
13c5f8356c chore(deps): update non-major-updates 2026-03-10 13:21:37 +00:00
GitHub Actions
95c3adfa61 fix: update dependencies in package-lock.json for improved compatibility 2026-03-10 12:24:08 +00:00
GitHub Actions
ef71f66029 feat: add Telegram notification provider support
- Updated API to support Telegram as a notification provider type.
- Enhanced tests to cover Telegram provider creation, updates, and token handling.
- Modified frontend forms to include Telegram-specific fields and validation.
- Added localization strings for Telegram provider.
- Implemented security measures to ensure bot tokens are not exposed in API responses.
2026-03-10 12:14:57 +00:00
GitHub Actions
317bff326b fix: update component styles for consistency and improved layout 2026-03-09 20:15:19 +00:00
GitHub Actions
542d4ff3ee fix: replace flex-shrink-0 with shrink-0 for consistent styling across components 2026-03-09 20:03:57 +00:00
GitHub Actions
82a55da026 chore: add @types/eslint-plugin-jsx-a11y as a dependency 2026-03-09 19:46:20 +00:00
GitHub Actions
0535f50d89 fix(deps): update @types/node to version 25.4.0 for improved compatibility 2026-03-09 19:14:11 +00:00
GitHub Actions
fc5cb0eb88 fix(deps): update @types/node to version 25.4.0 for improved compatibility 2026-03-09 19:13:45 +00:00
Jeremy
524d363e27 Merge pull request #820 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-09 15:10:39 -04:00
renovate[bot]
e2ebdb37f0 fix(deps): update non-major-updates 2026-03-09 18:49:35 +00:00
Jeremy
539dd1bff4 Merge pull request #817 from Wikid82/hotfix/docker_build
fix(docker): update CADDY_VERSION to 2.11.2 for improved stability
2026-03-09 14:46:47 -04:00
Jeremy
f8ec567a35 Merge pull request #818 from Wikid82/hotfix/docker_build
fix(docker): update CADDY_VERSION to 2.11.2 for improved stability
2026-03-09 14:46:12 -04:00
Jeremy
c758c9d3ab Merge pull request #813 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-09 13:48:00 -04:00
Jeremy
bfe535d36a Merge pull request #816 from Wikid82/hotfix/docker_build
fix(docker): update CADDY_VERSION to 2.11.2 for improved stability
2026-03-09 13:47:14 -04:00
GitHub Actions
aaf52475ee fix(docker): update Caddy version to 2.11.2 for consistency across documentation and scripts 2026-03-09 16:51:01 +00:00
renovate[bot]
424dc43652 fix(deps): update non-major-updates 2026-03-09 16:47:48 +00:00
GitHub Actions
cd35f6d8c7 fix(docker): update CADDY_CANDIDATE_VERSION to 2.11.2 for consistency 2026-03-09 16:47:48 +00:00
GitHub Actions
85b0bb1f5e fix(docker): update CADDY_VERSION to 2.11.2 for improved stability 2026-03-09 16:40:30 +00:00
GitHub Actions
b0001e4d50 fix: update flatted to version 3.4.1 and i18next to version 25.8.15 2026-03-09 13:12:19 +00:00
GitHub Actions
a77b6c5d3e fix: update tar package to version 7.5.11 2026-03-09 13:11:48 +00:00
GitHub Actions
3414c7c941 fix: update modernc.org/libc to v1.70.0 and golang.org/x/mod to v0.33.0 2026-03-09 13:10:46 +00:00
GitHub Actions
332872c7f5 fix: update Coraza Caddy version to 2.2.0 2026-03-09 12:48:55 +00:00
GitHub Actions
c499c57296 fix: update Caddy security version to 1.1.44 2026-03-09 12:39:22 +00:00
Jeremy
912bb7c577 Merge pull request #800 from Wikid82/feature/beta-release
feat: Enable Email Notifications
2026-03-09 08:36:53 -04:00
Jeremy
36d561bbb8 Merge pull request #815 from Wikid82/nightly
Weekly: Promote nightly to main (2026-03-09)
2026-03-09 08:36:28 -04:00
Jeremy
fccb1f06ac Merge pull request #814 from Wikid82/bot/update-geolite2-checksum
chore(docker): update GeoLite2-Country.mmdb checksum
2026-03-09 08:36:09 -04:00
Wikid82
cf46ff0a3b chore(docker): update GeoLite2-Country.mmdb checksum
Automated checksum update for GeoLite2-Country.mmdb database.

Old: d3031e02196523cbb5f74291122033f2be277b2130abedd4b5bee52ba79832be
New: b79afc28a0a52f89c15e8d92b05c173f314dd4f687719f96cf921012d900fcce

Auto-generated by: .github/workflows/update-geolite2.yml
2026-03-09 02:56:06 +00:00
GitHub Actions
6a37a906ce fix: update flatted and katex packages to latest versions 2026-03-09 00:52:39 +00:00
GitHub Actions
0f823956c6 fix: add email service check in ShouldUseNotify method 2026-03-09 00:49:07 +00:00
GitHub Actions
703108051a fix: correct spelling of "Commit" in agent documentation 2026-03-09 00:45:50 +00:00
GitHub Actions
795486e5b2 fix: correct typo in Multi-Commit Slicing Protocol section 2026-03-09 00:44:10 +00:00
GitHub Actions
799ca8c5f9 fix: enhance decompression limit check to prevent false positives for valid files 2026-03-09 00:42:23 +00:00
GitHub Actions
9cc7393e7b fix: update digest references in nightly build workflow to use output from resolve_digest step 2026-03-09 00:28:55 +00:00
GitHub Actions
791e812c3c fix: add assertion for ExpiresAt field in ManualChallenge struct 2026-03-09 00:09:14 +00:00
GitHub Actions
187c3aea68 fix: remove unused tags output from build-and-push-nightly job 2026-03-09 00:06:00 +00:00
GitHub Actions
d7de28a040 fix: allow saving email notification providers and render HTML body correctly 2026-03-08 20:26:13 +00:00
GitHub Actions
d1baf6f1b0 feat: implement email provider testing functionality and corresponding unit tests 2026-03-08 16:14:08 +00:00
GitHub Actions
3201830405 chore: update dependencies for golang.org/x/time, golang.org/x/arch, and golang.org/x/sys 2026-03-08 15:52:44 +00:00
GitHub Actions
728a55f1d8 fix: simplify frontend lint command in lefthook configuration 2026-03-08 08:06:50 +00:00
GitHub Actions
d3ef8d83b3 fix(frontend): resolve ESLint crash and repair lint configuration
- Scope base JS/TS configs to only JS/TS file extensions, preventing
  TypeError when ESLint applies core rules to markdown/CSS/JSON files
- Remove silent data loss from duplicate JSON keys in five translation
  files where the second dashboard block was overriding the first
- Fix unsafe optional chaining in CredentialManager that would throw
  TypeError when providerTypeInfo is undefined
- Remove stale eslint-disable directive for a rule now handled globally
  by the unused-imports plugin
- Downgrade high-volume lint rules (testing-library, jsx-a11y, import-x,
  vitest) from error to warn to unblock development while preserving
  visibility for incremental cleanup
2026-03-08 07:45:01 +00:00
GitHub Actions
c4e8d6c8ae chore: add unit tests for certificate handler, logs websocket upgrader, config loading, and mail service 2026-03-08 05:45:21 +00:00
GitHub Actions
698ad86d17 chore: structured autonomy commands for planning, generating, and implementing features
- Create sa-generate.md for generating implementation documentation from plans
- Create sa-implement.md for executing implementation plans step-by-step
- Create sa-plan.md for collaborating with users to design development plans
- Add security scan commands for CodeQL, Docker images, Go vulnerabilities, and GORM
- Implement SQL code review and optimization commands
- Add supply chain vulnerability remediation process
- Introduce backend and frontend test commands with coverage checks
- Update settings.json for command permissions
- Document governance, project overview, code quality rules, and critical architecture rules in CLAUDE.md
- Establish root cause analysis protocol and definition of done for development
2026-03-08 05:45:21 +00:00
Jeremy
2240c4c629 Merge pull request #812 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update release-drafter/release-drafter digest to 6a93d82 (feature/beta-release)
2026-03-07 18:01:09 -05:00
GitHub Actions
65b82a8e08 feat: add email notification provider with HTML templates
- Implemented email notification functionality in the NotificationService.
- Added support for rendering email templates based on event types.
- Created HTML templates for various notification types (security alerts, SSL events, uptime events, and system events).
- Updated the dispatchEmail method to utilize the new email templates.
- Added tests for email template rendering and fallback mechanisms.
- Enhanced documentation to include email notification setup and usage instructions.
- Introduced end-to-end tests for the email notification provider in the settings.
2026-03-07 19:54:21 +00:00
renovate[bot]
8032fb5b41 chore(deps): update non-major-updates 2026-03-07 19:54:06 +00:00
Jeremy
56fde3cbe1 Merge pull request #811 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update dependency knip to ^5.86.0 (feature/beta-release)
2026-03-07 14:53:33 -05:00
renovate[bot]
bccbb708f1 chore(deps): update dependency knip to ^5.86.0 2026-03-07 17:27:31 +00:00
GitHub Actions
80b1ed7fab fix: update knip to version 5.86.0 and upgrade oxc-resolver to 11.19.1; add unbash and yaml packages 2026-03-07 13:59:37 +00:00
GitHub Actions
e68035fe30 fix: add Trivy ignore for CVE-2026-22184 and update expiry date for CVE-2026-22184 in Grype configuration 2026-03-07 13:56:01 +00:00
GitHub Actions
80ecb7de7f fix: enhance vulnerability reporting in nightly build with detailed triage information 2026-03-07 13:38:16 +00:00
GitHub Actions
75cd0a4d9c fix: update nightly branch checkout reference to support manual triggers 2026-03-07 12:58:40 +00:00
GitHub Actions
2824a731f5 fix: improve Alpine image digest resolution in nightly build workflow 2026-03-07 12:40:00 +00:00
GitHub Actions
2dbb00036d fix: resolve image digest from GHCR API for nightly builds 2026-03-07 12:25:57 +00:00
GitHub Actions
0ad0c2f2c4 fix: improve error handling for empty build digest in Syft SBOM scan 2026-03-07 12:18:20 +00:00
GitHub Actions
104f0eb6ee fix: add error handling for empty build digest in Syft SBOM scan 2026-03-07 12:04:15 +00:00
GitHub Actions
c144bb2b97 fix: enhance email notification formatting with HTML for improved readability 2026-03-07 05:53:46 +00:00
Jeremy
f50b05519b Merge pull request #810 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update aquasecurity/trivy-action action to v0.35.0 (feature/beta-release)
2026-03-07 00:35:57 -05:00
GitHub Actions
ca3c1085ac fix: update notification messages for various handlers to improve clarity and consistency 2026-03-07 05:16:07 +00:00
renovate[bot]
4cee4f01f3 chore(deps): update aquasecurity/trivy-action action to v0.35.0 2026-03-07 04:29:40 +00:00
GitHub Actions
82e2134333 fix: remove security-experimental queries from CodeQL configuration to prevent false positives 2026-03-07 03:48:04 +00:00
GitHub Actions
6add11f1d2 fix: update pre-commit hooks to process all files instead of staged files for end-of-file and trailing whitespace checks 2026-03-07 03:44:18 +00:00
GitHub Actions
744b6aeff5 fix: improve pagination handling and prevent decompression bombs in backup service
fix: enhance JWT secret management to avoid hardcoded values and ensure security
feat: add SMTP address sanitization to prevent email header injection vulnerabilities
2026-03-07 03:39:54 +00:00
GitHub Actions
92310a8b3e fix: update CodeQL queries to include security-experimental suite for enhanced analysis 2026-03-07 02:42:42 +00:00
GitHub Actions
d74ea47e2c fix: enhance pre-commit hooks to auto-fix end-of-file and trailing whitespace issues, and re-stage modified files for review 2026-03-07 02:26:30 +00:00
GitHub Actions
c665f62700 chore: migrate pre-commit hooks to lefthook for improved performance and consistency 2026-03-07 02:20:29 +00:00
GitHub Actions
37471141e8 fix: update eslint and related dependencies to latest versions for improved functionality 2026-03-07 02:07:31 +00:00
GitHub Actions
81497beb4b fix: update opentelemetry dependencies to latest versions for improved performance 2026-03-07 02:06:15 +00:00
GitHub Actions
2d40f34ff0 chore: add lefthook configuration for pre-commit and pre-push pipelines 2026-03-07 02:02:37 +00:00
Jeremy
801760add1 Potential fix for code scanning alert no. 1271: Email content injection
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-03-06 15:30:55 -05:00
GitHub Actions
4ebf8d23fe fix: enhance email sanitization by trimming whitespace and normalizing input 2026-03-06 20:18:51 +00:00
GitHub Actions
77a7368c5d fix: update caddy-security version to 1.1.43 for improved security 2026-03-06 20:18:36 +00:00
Jeremy
51a01c4f7b Merge pull request #809 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-06 15:01:01 -05:00
renovate[bot]
13d31dd922 fix(deps): update non-major-updates 2026-03-06 20:00:48 +00:00
GitHub Actions
c9bb303a7d fix: update dependencies for eslint, caniuse-lite, react-i18next, tldts, and tldts-core to latest versions for improved functionality 2026-03-06 19:59:45 +00:00
GitHub Actions
6ebfd417e3 fix: update katex and tldts dependencies to latest versions for improved functionality 2026-03-06 19:58:58 +00:00
GitHub Actions
b527470e75 fix: update opentelemetry dependencies to v1.42.0 for improved functionality and performance 2026-03-06 19:58:19 +00:00
GitHub Actions
89b4d88eb1 fix: enhance email content sanitization to prevent CR/LF injection and improve security 2026-03-06 19:56:22 +00:00
GitHub Actions
a69f698440 fix: enhance WebSocket origin check and improve email validation in mail service 2026-03-06 13:50:59 +00:00
GitHub Actions
ee224adcf1 fix: update notification provider type in tests and enhance email injection sanitization 2026-03-06 06:31:11 +00:00
GitHub Actions
5bbae48b6b chore(docker): wire all workflows to single-source version ARGs
The Dockerfile already centralizes all version pins into top-level ARGs
(GO_VERSION, ALPINE_IMAGE, CROWDSEC_VERSION, EXPR_LANG_VERSION, XNET_VERSION).
This change closes the remaining gaps so those ARGs are the single source of
truth end-to-end:

- nightly-build.yml now resolves the Alpine image digest at build time and
  passes ALPINE_IMAGE as a build-arg, matching the docker-build.yml pattern.
  Previously, nightly images were built with the Dockerfile ARG default and
  without a pinned digest, making runtime Alpine differ from docker-build.yml.

- six CI workflows (quality-checks, codecov-upload, benchmark, e2e-tests-split,
  release-goreleaser, codeql) declared a GO_VERSION env var but their setup-go
  steps ignored it and hardcoded the version string directly. They now reference
  ${{ env.GO_VERSION }}, so Renovate only needs to update one value per file
  and the env var actually serves its purpose.

- codeql.yml had no GO_VERSION env var at all; one is now added alongside the
  existing GOTOOLCHAIN: auto entry.

When Renovate bumps Go, it updates the env var at the top of each workflow and
the Dockerfile ARG — zero manual hunting required.
2026-03-06 03:57:18 +00:00
GitHub Actions
abcfd62b21 fix: update Go version to 1.26.1 in CodeQL workflow for consistency and security improvements 2026-03-06 03:20:37 +00:00
GitHub Actions
10d952a22e fix: update golang version to 1.26.1-alpine in Dockerfile for security improvements 2026-03-06 03:14:16 +00:00
GitHub Actions
635caf0f9a fix: update Caddy version to 2.11.2 in architecture and compatibility matrix for consistency 2026-03-06 02:56:31 +00:00
GitHub Actions
2266a8d051 fix: update golang version to 1.26.1-alpine in Dockerfile for consistency and security improvements 2026-03-06 02:44:07 +00:00
GitHub Actions
b292a1b793 fix: update Go version to 1.26.1 in multiple workflow files for consistency and security improvements 2026-03-06 02:35:36 +00:00
GitHub Actions
bf398a1cb2 fix: update Go version to 1.26.1 in Dockerfile and go.work for security improvements 2026-03-06 02:22:38 +00:00
GitHub Actions
e7c98e5526 fix: update golang version to 1.26.1-alpine in Dockerfile for security improvements 2026-03-06 02:15:37 +00:00
Jeremy
99ff0a34e3 Merge pull request #808 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update non-major-updates (feature/beta-release)
2026-03-05 21:07:44 -05:00
GitHub Actions
c42b7f5a5b fix: update golang.org/x/net to version 0.51.0 in Dockerfile 2026-03-06 02:06:49 +00:00
GitHub Actions
ed89295012 feat: wire MailService into notification dispatch pipeline (Stage 3)
Unifies the two previously independent email subsystems — MailService
(net/smtp transport) and NotificationService (HTTP-based providers) —
so email can participate in the notification dispatch pipeline.

Key changes:
- SendEmail signature updated to accept context.Context and []string
  recipients to enable timeout propagation and multi-recipient dispatch
- NotificationService.dispatchEmail() wires MailService as a first-class
  provider type with IsConfigured() guard and 30s context timeout
- 'email' added to isSupportedNotificationProviderType() and
  supportsJSONTemplates() returns false for email (plain/HTML only)
- settings_handler.go test-email endpoint updated to new SendEmail API
- Frontend: 'email' added to provider type union in notifications.ts,
  Notifications.tsx shows recipient field and hides URL/token fields for
  email providers
- All existing tests updated to match new SendEmail signature
- New tests added covering dispatchEmail paths, IsConfigured guards,
  recipient validation, and context timeout behaviour

Also fixes confirmed false-positive CodeQL go/email-injection alerts:
- smtp.SendMail, sendSSL w.Write, and sendSTARTTLS w.Write sites now
  carry inline codeql[go/email-injection] annotations as required by the
  CodeQL same-line suppression spec; preceding-line annotations silently
  no-op in current CodeQL versions
- auth_handler.go c.SetCookie annotated for intentional Secure=false on
  local non-HTTPS loopback (go/cookie-secure-not-set warning only)

Closes part of #800
2026-03-06 02:06:49 +00:00
renovate[bot]
834907cb5d chore(deps): update non-major-updates 2026-03-06 02:02:10 +00:00
Jeremy
e295a1f64c Merge pull request #806 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update dependency @types/node to ^25.3.4 (feature/beta-release)
2026-03-05 20:58:50 -05:00
Jeremy
7cec4d7979 Merge pull request #807 from Wikid82/renovate/feature/beta-release-docker-build-push-action-7.x
chore(deps): update docker/build-push-action action to v7 (feature/beta-release)
2026-03-05 20:58:10 -05:00
renovate[bot]
132bbbd657 chore(deps): update docker/build-push-action action to v7 2026-03-06 01:07:01 +00:00
renovate[bot]
833220f1cb chore(deps): update dependency @types/node to ^25.3.4 2026-03-06 01:06:56 +00:00
Jeremy
e1e422bfc6 Merge pull request #805 from Wikid82/renovate/feature/beta-release-docker-metadata-action-6.x
chore(deps): update docker/metadata-action action to v6 (feature/beta-release)
2026-03-05 20:02:26 -05:00
Jeremy
e4b6ce62cd Merge pull request #804 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-05 20:01:13 -05:00
renovate[bot]
396d01595e chore(deps): update docker/metadata-action action to v6 2026-03-05 21:12:58 +00:00
renovate[bot]
6a13e648ea fix(deps): update non-major-updates 2026-03-05 21:12:51 +00:00
GitHub Actions
5fa0cff274 fix: eliminate wall-clock race in TestApplyRepullsOnCacheExpired
The test used a 5ms TTL with a 10ms wall-clock sleep to simulate cache
expiry. On loaded CI runners (Azure eastus), the repull HTTP round-trip
plus disk I/O for Store easily exceeded 5ms, causing the freshly written
cache entry to also appear expired when Load was called immediately after,
producing a spurious 'cache expired' error.

HubCache already exposes a nowFn field for deterministic time injection.
Replace the sleep-based approach with a nowFn that advances the clock 2
hours, making the initial entry appear expired to Apply while keeping the
freshly re-stored entry (retrieved_at ≈ now+2h, TTL=1h) valid for the
final assertion.
2026-03-05 20:20:14 +00:00
GitHub Actions
bcb2748f89 fix: update CADDY_SECURITY_VERSION to 1.1.42 in Dockerfile 2026-03-05 20:09:13 +00:00
GitHub Actions
e68a6039b9 fix: update css-syntax-patches-for-csstree to version 1.1.0 and react-i18next to version 16.5.5 in package-lock.json 2026-03-05 20:04:48 +00:00
GitHub Actions
0199f93994 fix: update katex version to 0.16.35 in package-lock.json 2026-03-05 20:04:30 +00:00
GitHub Actions
f2cf5c3508 chore: add coverage for default false state of email notifications feature flag 2026-03-05 14:58:21 +00:00
GitHub Actions
1d39756713 fix: update css-tree version to 3.2.1 in package-lock.json 2026-03-05 14:56:25 +00:00
GitHub Actions
71455ef88f fix: update katex version to 0.16.34 in package-lock.json 2026-03-05 14:56:16 +00:00
Jeremy
99b8ed875e Merge pull request #803 from Wikid82/renovate/feature/beta-release-docker-setup-buildx-action-4.x
chore(deps): update docker/setup-buildx-action action to v4 (feature/beta-release)
2026-03-05 09:41:29 -05:00
Jeremy
8242666678 Merge pull request #802 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update github/codeql-action digest to 0c0c5dc (feature/beta-release)
2026-03-05 09:40:59 -05:00
renovate[bot]
5aade0456e chore(deps): update docker/setup-buildx-action action to v4 2026-03-05 14:39:50 +00:00
renovate[bot]
479f56f3e8 chore(deps): update github/codeql-action digest to 0c0c5dc 2026-03-05 14:39:43 +00:00
GitHub Actions
8c7a55eaa2 fix: pin Trivy binary version to v0.69.3 in all CI workflows 2026-03-05 13:04:33 +00:00
GitHub Actions
924b8227b5 fix: add bash to Dockerfile dependencies for xcaddy build process 2026-03-05 07:15:37 +00:00
Jeremy
c3fa29d13c Merge branch 'development' into feature/beta-release 2026-03-05 02:13:58 -05:00
Jeremy
e5dab58b42 Merge pull request #801 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update dependency tar to ^7.5.10 (feature/beta-release)
2026-03-05 02:13:27 -05:00
Jeremy
22496a44a8 Merge branch 'feature/beta-release' into renovate/feature/beta-release-non-major-updates 2026-03-05 02:07:52 -05:00
GitHub Actions
87e6762611 fix: pin alpine and golang images with specific SHA256 digests in Dockerfile 2026-03-05 07:05:04 +00:00
GitHub Actions
ddc79865bc test: cover email provider paths in SendExternal and TestProvider
Two unit tests cover the code paths introduced when email was registered
as a recognised notification provider type in Stage 2.

- TestSendExternal_EmailProviderSkipsJSONTemplate exercises the goroutine
  warn path where an enabled email provider passes isDispatchEnabled but
  fails supportsJSONTemplates, producing a warning log without panicking
- TestTestProvider_EmailRejectsJSONTemplateStep asserts TestProvider
  returns a clear error for email providers because the JSON template
  dispatch path does not apply to email delivery

Patch coverage: 6/6 changed lines covered (100%)
2026-03-05 06:57:37 +00:00
renovate[bot]
6ee185c538 chore(deps): update dependency tar to ^7.5.10 2026-03-05 06:39:58 +00:00
GitHub Actions
367943b543 fix: update caddy-security version to 1.1.38 in Dockerfile 2026-03-05 06:36:59 +00:00
GitHub Actions
08e7eb7525 fix: update css-tree and mdn-data package versions to latest 2026-03-05 04:44:10 +00:00
GitHub Actions
35ca99866a fix: update tar package version from 7.5.9 to 7.5.10 2026-03-05 04:43:10 +00:00
GitHub Actions
2f83526966 fix: resolve email provider test regression from Stage 2 flag registration
After email was recognised as a supported provider type, the existing
rejection assertion for unsupported types incorrectly included email
in its denial list, causing a nil-dereference panic.

- Remove email from the unsupported-type rejection list and cover it
  in the accepted-types path instead
- Correct allFeaturesEnabled fixture to set email flag to true, keeping
  the fixture semantically consistent with all other service flags
2026-03-05 04:22:04 +00:00
GitHub Actions
5a58404e1b feat: register email as feature-flagged notification service
Add email as a recognized, feature-flagged notification service type.
The flag defaults to false and acts as a dispatch gate alongside the
existing discord, gotify, and webhook notification service flags.

- Add FlagEmailServiceEnabled constant to the notifications feature flag
  registry with the canonical key convention
- Register the flag in the handler defaults so it appears in the feature
  flags API response with a false default
- Recognise 'email' as a supported notification provider type so that
  providers of this type pass the type validation gate
- Gate email dispatch on the new flag in isDispatchEnabled() following
  the same pattern as gotify and webhook service flags
- Expand the E2E test fixtures FeatureFlags interface to include the new
  flag key so typed fixture objects remain accurate

No email message dispatch is wired in this commit; the flag registration
alone makes the email provider type valid and toggleable.
2026-03-05 03:36:27 +00:00
GitHub Actions
8ea907066b chore: remove Shoutrrr residue and dead notification legacy code
Remove all deprecated Shoutrrr integration artifacts and dead legacy fallback
code from the notification subsystem.

- Remove legacySendFunc field, ErrLegacyFallbackDisabled error, and
  legacyFallbackInvocationError() from notification service
- Delete ShouldUseLegacyFallback() from notification router; simplify
  ShouldUseNotify() by removing now-dead providerEngine parameter
- Remove EngineLegacy engine constant; EngineNotifyV1 is the sole engine
- Remove legacy.fallback_enabled feature flag, retiredLegacyFallbackEnvAliases,
  and parseFlagBool/resolveRetiredLegacyFallback helpers from flags handler
- Remove orphaned EmailRecipients field from NotificationConfig model
- Delete feature_flags_coverage_v2_test.go (tested only the retired flag path)
- Delete security_notifications_test.go.archived (stale archived file)
- Move FIREFOX_E2E_FIXES_SUMMARY.md to docs/implementation/
- Remove root-level scan artifacts tracked in error; add gitignore patterns to
  prevent future tracking of trivy-report.json and related outputs
- Update ARCHITECTURE.instructions.md: Notifications row Shoutrrr → Notify

No functional changes to active notification dispatch or mail delivery.
2026-03-05 00:41:42 +00:00
GitHub Actions
ffe5d951e0 fix: update terminology from "PR Slicing Strategy" to "Cmmit Slicing Strategy" in agent instructions 2026-03-04 21:02:59 +00:00
Jeremy
e5af7d98d1 Merge pull request #799 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update github/codeql-action digest to b6dfacb (feature/beta-release)
2026-03-04 13:38:58 -05:00
GitHub Actions
27c252600a chore: git cache cleanup 2026-03-04 18:34:49 +00:00
GitHub Actions
c32cce2a88 chore: git cache cleanup 2026-03-04 18:34:39 +00:00
renovate[bot]
c01c6c6225 chore(deps): update github/codeql-action digest to b6dfacb 2026-03-04 18:33:32 +00:00
Jeremy
a66659476d Merge pull request #794 from Wikid82/feature/beta-release
Restructure User Management
2026-03-04 13:31:05 -05:00
GitHub Actions
7a8b0343e4 fix: update user record to trigger user_update audit event in E2E workflow 2026-03-04 15:36:02 +00:00
Jeremy
cc3077d709 Merge pull request #798 from Wikid82/renovate/feature/beta-release-docker-login-action-4.x
chore(deps): update docker/login-action action to v4 (feature/beta-release)
2026-03-04 08:36:19 -05:00
renovate[bot]
d1362a7fba chore(deps): update docker/login-action action to v4 2026-03-04 13:35:15 +00:00
GitHub Actions
4e9e1919a8 fix: update UserProfile role type and enhance API response typings for getProfile and updateProfile 2026-03-04 12:43:41 +00:00
GitHub Actions
f19f53ed9a fix(e2e): update user lifecycle audit entry checks to ensure both user_create and user_update events are present 2026-03-04 12:41:56 +00:00
GitHub Actions
f062dc206e fix: restrict email changes for non-admin users to profile settings 2026-03-04 12:38:28 +00:00
GitHub Actions
a97cb334a2 fix(deps): update @exodus/bytes, electron-to-chromium, and node-releases to latest versions 2026-03-04 12:28:05 +00:00
Jeremy
cf52a943b5 Merge pull request #797 from Wikid82/renovate/feature/beta-release-docker-setup-qemu-action-4.x
chore(deps): update docker/setup-qemu-action action to v4 (feature/beta-release)
2026-03-04 07:18:01 -05:00
Jeremy
46d0ecc4fb Merge pull request #796 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-04 07:17:31 -05:00
renovate[bot]
348c5e5405 chore(deps): update docker/setup-qemu-action action to v4 2026-03-04 12:16:35 +00:00
renovate[bot]
25dbe82360 fix(deps): update non-major-updates 2026-03-04 12:16:29 +00:00
GitHub Actions
fc404da455 fix(e2e): resolve shard 4 failures from 3-tier role model changes
Three tests broke when the Admin/User/Passthrough privilege model replaced
the old admin/user/guest hierarchy in PR-3.

- user-management: tighten heading locator to name='User Management' to avoid
  strict mode violation; the settings layout now renders a second h1
  ('Settings') alongside the page content heading
- user-lifecycle: update audit trail assertion from 2 to 1; users are now
  created with a role in a single API call so the backend does not emit a
  user_update audit entry when STEP 2 sends the same role value as creation
- auth-fixtures: replace invalid role='guest' with role='passthrough' in the
  guestUser fixture; the 'guest' role was removed in PR-3 and 'passthrough' is
  the equivalent lowest-privilege role in the new model

Verified: all three previously-failing tests now pass locally.
2026-03-03 13:10:44 +00:00
GitHub Actions
ed27fb0da9 fix(e2e): update account navigation locator and skip legacy Account.tsx test sections
The Account.tsx page was removed in PR-2b and replaced by UsersPage.tsx with
a UserDetailModal. Several E2E test sections still referenced UI elements that
only existed in the deleted page, causing CI failures across shards.

- admin-onboarding: update header profile link locator from /settings/account
  to /settings/users to match the new navigation target in Layout.tsx
- account-settings: skip five legacy test sections (Profile Management,
  Certificate Email, Password Change, API Key Management, Accessibility) that
  reference deleted Account.tsx elements (#profile-name, #profile-email,
  #useUserEmail, #cert-email) or assume these fields are directly on the page
  rather than inside the UserDetailModal
- Each skipped section includes an explanatory comment pointing to the PR-3
  'Self-Service Profile via Users Page (F10)' suite as the equivalent coverage

Verified: admin-onboarding 8/8 pass; account-settings 8 pass / 20 skipped
2026-03-03 10:27:13 +00:00
GitHub Actions
afbd50b43f fix: update @floating-ui and caniuse-lite packages to latest versions for improved functionality 2026-03-03 09:17:54 +00:00
GitHub Actions
ad2d30b525 fix: update postcss to version 8.5.8 for improved stability 2026-03-03 09:17:25 +00:00
GitHub Actions
a570a3327f fix: update opentelemetry http instrumentation to v0.66.0 2026-03-03 09:16:34 +00:00
GitHub Actions
0fd00575a2 feat: Add passthrough role support and related tests
- Implemented middleware to restrict access for passthrough users in management routes.
- Added unit tests for management access requirements based on user roles.
- Updated user model tests to include passthrough role validation.
- Enhanced frontend user management to support passthrough role in invite modal.
- Created end-to-end tests for passthrough user access restrictions and navigation visibility.
- Verified self-service profile management for admins and regular users.
2026-03-03 09:14:33 +00:00
GitHub Actions
a3d1ae3742 fix: update checkout ref to use full GitHub ref path for accurate branch handling 2026-03-03 04:31:42 +00:00
GitHub Actions
6f408f62ba fix: prevent stale-SHA checkout in scheduled CodeQL security scan
The scheduled CodeQL analysis explicitly passed ref: github.sha, which
is frozen when a cron job is queued, not when it runs. Under load or
during a long queue, the analysis could scan code that is days old,
missing vulnerabilities introduced since the last scheduling window.

Replace with ref: github.ref_name so all trigger types — scheduled,
push, and pull_request — consistently scan the current HEAD of the
branch being processed.
2026-03-03 04:24:47 +00:00
GitHub Actions
e92e7edd70 fix: prevent stale-SHA checkout and pin caddy-security in weekly security rebuild
The scheduled weekly rebuild was failing because GitHub Actions froze
github.sha at job-queue time. When the Sunday cron queued a job on
March 1 with Feb 23 code (CADDY_VERSION=2.11.0-beta.2), that job ran
two days later on March 3 still using the old code, missing the caddy
version fix that had since landed on main.

Additionally, caddy-security was unpinned, so xcaddy auto-resolved it
to v1.1.36 which requires caddy/v2@v2.11.1 — conflicting with xcaddy's
internally bundled v2.11.0-beta.2 reference.

- Add ref: github.ref_name to checkout step so the rebuild always
  fetches current branch HEAD at run time, not the SHA frozen at queue
  time
- Add CADDY_SECURITY_VERSION=1.1.36 ARG to pin the caddy-security
  plugin to a known-compatible version; pass it via --with so xcaddy
  picks up the pinned release
- Add --with github.com/caddyserver/caddy/v2@v${CADDY_TARGET_VERSION}
  to force xcaddy to use the declared Caddy version, overriding its own
  internal go.sum pin for caddy
- Add Renovate custom manager for CADDY_SECURITY_VERSION so future
  caddy-security releases trigger an automated PR instead of silently
  breaking the build

Fixes weekly security rebuild CI failures introduced ~Feb 22 when
caddy-security v1.1.36 was published.
2026-03-03 04:22:39 +00:00
GitHub Actions
4e4c4581ea fix: update Caddy Server version to 2.11.1 in architecture documentation 2026-03-03 03:52:57 +00:00
GitHub Actions
3f12ca05a3 feat: implement role-based access for settings route and add focus trap hook
- Wrapped the Settings component in RequireRole to enforce access control for admin and user roles.
- Introduced a new custom hook `useFocusTrap` to manage focus within modal dialogs, enhancing accessibility.
- Applied the focus trap in InviteModal, PermissionsModal, and UserDetailModal to prevent focus from leaving the dialog.
- Updated PassthroughLanding to focus on the heading when the component mounts.
2026-03-03 03:10:02 +00:00
GitHub Actions
a681d6aa30 feat: remove Account page and add PassthroughLanding page
- Deleted the Account page and its associated logic.
- Introduced a new PassthroughLanding page for users without management access.
- Updated Settings page to conditionally display the Users link for admin users.
- Enhanced UsersPage to support passthrough user role, including invite functionality and user detail modal.
- Updated tests to reflect changes in user roles and navigation.
2026-03-03 03:10:02 +00:00
GitHub Actions
3632d0d88c fix: user roles to use UserRole type and update related tests
- Changed user role representation from string to UserRole type in User model.
- Updated role assignments in various services and handlers to use the new UserRole constants.
- Modified middleware to handle UserRole type for role checks.
- Refactored tests to align with the new UserRole type.
- Added migration function to convert legacy "viewer" roles to "passthrough".
- Ensured all role checks and assignments are consistent across the application.
2026-03-03 03:10:02 +00:00
GitHub Actions
a1a9ab2ece chore(docs): archive uptime monitoring regression investigation plan to address false DOWN states 2026-03-03 03:10:02 +00:00
Jeremy
9c203914dd Merge pull request #795 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update dependency postcss to ^8.5.8 (feature/beta-release)
2026-03-02 19:25:08 -05:00
renovate[bot]
6cfe8ca9f2 chore(deps): update dependency postcss to ^8.5.8 2026-03-03 00:22:16 +00:00
Jeremy
938b170d98 Merge branch 'development' into feature/beta-release 2026-03-02 17:41:57 -05:00
Jeremy
9d6d2cbe53 Merge pull request #793 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update dependency postcss to ^8.5.7 (feature/beta-release)
2026-03-02 17:33:09 -05:00
renovate[bot]
136dd7ef62 chore(deps): update dependency postcss to ^8.5.7 2026-03-02 22:31:09 +00:00
Jeremy
f0c754cc52 Merge pull request #785 from Wikid82/feature/beta-release
Save and Import Functions Hotfix
2026-03-02 17:28:03 -05:00
GitHub Actions
28be62dee0 fix(tests): update cancel endpoint mock to match DELETE requests with session UUID 2026-03-02 22:09:53 +00:00
Jeremy
49bfbf3f76 Merge branch 'development' into feature/beta-release 2026-03-02 16:04:39 -05:00
GitHub Actions
2f90d936bf fix(tests): simplify back/cancel button handling in cross-browser import tests 2026-03-02 21:02:34 +00:00
GitHub Actions
4a60400af9 chore(deps): add tracking for Syft and Grype versions in workflows and scripts 2026-03-02 21:01:42 +00:00
GitHub Actions
18d0c235fa fix(deps): update OpenTelemetry dependencies to v1.41.0 2026-03-02 20:31:45 +00:00
GitHub Actions
fe8225753b fix(tests): remove visibility check for banner in cancel session flow 2026-03-02 20:28:40 +00:00
GitHub Actions
273fb3cf21 fix(tests): improve cancel session flow in cross-browser import tests 2026-03-02 20:04:34 +00:00
GitHub Actions
e3b6693402 fix: correct version-check hook to use global latest tag
The pre-commit version check hook was incorrectly using `git describe`
to find the latest tag, which only traverses the current branch's
ancestry. On feature branches that predate release tags applied to
main/nightly, this caused false failures — reporting v0.19.1 as latest
even though v0.20.0 and v0.21.0 existed globally.

Replaced with `git tag --sort=-v:refname | grep semver | head -1` so
the check always compares .version against the true latest release tag
in the repository, independent of which branch is checked out.
2026-03-02 19:52:47 +00:00
Jeremy
ac915f14c7 Merge pull request #792 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update aquasecurity/trivy-action action to v0.34.2 (feature/beta-release)
2026-03-02 14:08:07 -05:00
renovate[bot]
5ee52dd4d6 chore(deps): update aquasecurity/trivy-action action to v0.34.2 2026-03-02 19:02:20 +00:00
GitHub Actions
b5fd5d5774 fix(tests): update import handler test to use temporary directory for Caddyfile path 2026-03-02 15:29:49 +00:00
Jeremy
ae4f5936b3 Merge pull request #787 from Wikid82/main
Propagate changes from main into development
2026-03-02 10:29:25 -05:00
GitHub Actions
5017fdf4c1 fix: correct spelling of 'linting' in Management agent instructions 2026-03-02 15:25:36 +00:00
GitHub Actions
f0eda7c93c chore: remove workflow_dispatch trigger from quality checks workflow 2026-03-02 15:14:25 +00:00
GitHub Actions
f60a99d0bd fix(tests): update route validation functions to ensure canonical success responses in import/save regression tests 2026-03-02 15:05:05 +00:00
Jeremy
1440b2722e Merge pull request #786 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-02 10:02:56 -05:00
Jeremy
f58c96d29f Merge pull request #784 from Wikid82/nightly
Weekly Nightly Promotion
2026-03-02 10:00:05 -05:00
renovate[bot]
3b92700b5b fix(deps): update non-major-updates 2026-03-02 14:58:14 +00:00
GitHub Actions
5c0a543669 chore: update flatted, tldts, and tldts-core to version 7.0.24 in package-lock.json 2026-03-02 14:55:30 +00:00
GitHub Actions
317b695efb chore: update tldts and tldts-core to version 7.0.24 in package-lock.json 2026-03-02 14:54:51 +00:00
GitHub Actions
077e3c1d2b chore: add integration tests for import/save route regression coverage 2026-03-02 14:53:59 +00:00
GitHub Actions
b5c5ab0bc3 chore: add workflow_dispatch trigger to quality checks workflow 2026-03-02 14:53:59 +00:00
Jeremy
a6188bf2f1 Merge branch 'development' into feature/beta-release 2026-03-02 09:48:21 -05:00
Jeremy
2ecd6dd9d4 Merge branch 'main' into nightly 2026-03-02 09:38:57 -05:00
GitHub Actions
16752f4bb1 fixt(import): update cancel functions to accept session UUID and modify related tests 2026-03-02 14:30:24 +00:00
GitHub Actions
a75dd2dcdd chore: refactor agent tools and improve documentation
- Consolidated tools for Management, Planning, Playwright Dev, QA Security, and Supervisor agents to streamline functionality and reduce redundancy.
- Updated terminology from "Proper" fix to "Long Term" fix in Management agent for clarity on implementation choices.
- Added mandatory lintr and type checks before declaring slices "DONE" in Management agent to enhance code quality.
- Enhanced argument hints and descriptions across agents for better guidance on usage.
2026-03-02 14:24:31 +00:00
GitHub Actions
63e79664cc test(routes): add strict route matrix tests for import and save workflows 2026-03-02 14:11:54 +00:00
GitHub Actions
005b7bdf5b fix(handler): enforce session UUID requirement in Cancel method and add related tests 2026-03-02 14:11:20 +00:00
GitHub Actions
0f143af5bc fix(handler): validate session UUID in Cancel method of JSONImportHandler 2026-03-02 14:10:45 +00:00
GitHub Actions
76fb800922 fix(deps): update @csstools/css-syntax-patches-for-csstree and cssstyle to latest versions 2026-03-02 08:39:22 +00:00
Jeremy
58f5295652 Merge pull request #782 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-03-02 03:32:42 -05:00
renovate[bot]
0917a1ae95 fix(deps): update non-major-updates 2026-03-02 08:19:58 +00:00
Jeremy
409dc0526f Merge pull request #779 from Wikid82/feature/beta-release
Uptime Monitoring Hotfix
2026-03-01 23:10:57 -05:00
GitHub Actions
10259146df fix(uptime): implement initial uptime bootstrap logic and related tests 2026-03-02 03:40:37 +00:00
Jeremy
8cbd907d82 Merge pull request #781 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update non-major-updates (feature/beta-release)
2026-03-01 22:16:52 -05:00
Jeremy
ff5ef35a0f Merge pull request #780 from Wikid82/bot/update-geolite2-checksum
chore(docker): update GeoLite2-Country.mmdb checksum
2026-03-01 22:16:18 -05:00
renovate[bot]
fbb86b1cc3 chore(deps): update non-major-updates 2026-03-02 03:15:19 +00:00
Wikid82
0f995edbd1 chore(docker): update GeoLite2-Country.mmdb checksum
Automated checksum update for GeoLite2-Country.mmdb database.

Old: 86fe00e0272865b8bec79defca2e9fb19ad0cf4458697992e1a37ba89077c13a
New: d3031e02196523cbb5f74291122033f2be277b2130abedd4b5bee52ba79832be

Auto-generated by: .github/workflows/update-geolite2.yml
2026-03-02 02:53:18 +00:00
GitHub Actions
aaddb88488 fix(uptime): refine host monitor checks to short-circuit TCP monitors while allowing HTTP/HTTPS checks 2026-03-02 00:24:03 +00:00
GitHub Actions
f79f0218c5 fix(tests): update mock heartbeat generation to align with monitor's latest status 2026-03-01 17:38:01 +00:00
GitHub Actions
d94c9ba623 fix(tests): enhance overwrite resolution flow test to handle browser-specific authentication 2026-03-01 17:17:49 +00:00
GitHub Actions
0241de69f4 fix(uptime): enhance monitor status handling and display logic in MonitorCard 2026-03-01 16:33:09 +00:00
GitHub Actions
f20e789a16 fix(tests): increase timeout for ProxyHostForm tests to improve reliability 2026-03-01 16:30:51 +00:00
GitHub Actions
6f5c8873f9 fix(tests): refactor proxy host creation to use dynamic server URLs in uptime tests 2026-03-01 16:30:21 +00:00
GitHub Actions
7a12ab7928 fix(uptime): remove redundant host failure count reset logic 2026-03-01 16:26:24 +00:00
GitHub Actions
871adca270 fix(deps): update modernc.org/libc to v1.69.0 for improved compatibility 2026-03-01 14:08:13 +00:00
GitHub Actions
dbff270d22 fix(tests): update input handling in ProxyHostForm tests for improved reliability 2026-03-01 14:04:40 +00:00
GitHub Actions
8e1b9d91e2 fix(tests): enhance session handling and cleanup in Caddy import tests 2026-03-01 13:43:50 +00:00
GitHub Actions
67bcef32e4 fix(tests): improve header verification and response handling in Firefox import tests 2026-03-01 13:43:42 +00:00
GitHub Actions
739104e029 fix(workflows): update cron schedule for weekly security rebuild and nightly promotion 2026-03-01 13:14:25 +00:00
GitHub Actions
2204b7bd35 fix(tests): implement retry logic for session reset and navigation stability in Caddy import tests 2026-03-01 13:06:47 +00:00
GitHub Actions
fdbba5b838 fix(tests): remove redundant caddy-import spec exclusions for improved test coverage 2026-03-01 13:06:36 +00:00
GitHub Actions
4ff65c83be fix(tests): refactor CORS handling in Firefox import tests for improved clarity and reliability 2026-03-01 05:31:37 +00:00
GitHub Actions
3409e204eb fix(tests): enhance timeout handling for UI preconditions in import page navigation 2026-03-01 05:18:44 +00:00
GitHub Actions
61bb19e6f3 fix(tests): enhance session resume handling in import tests for improved reliability 2026-03-01 05:18:33 +00:00
GitHub Actions
3cc979f5b8 fix(tests): remove webkit-only test skipping logic for improved test execution 2026-03-01 05:16:38 +00:00
GitHub Actions
ef8f237233 fix(tests): remove redundant Firefox-only test skipping logic 2026-03-01 05:16:27 +00:00
GitHub Actions
43a63007a7 fix(tests): update testIgnore patterns to exclude specific caddy-import tests 2026-03-01 05:14:59 +00:00
GitHub Actions
404aa92ea0 fix(tests): improve response handling and session management in import tests 2026-03-01 05:11:18 +00:00
GitHub Actions
94356e7d4e fix(logging): convert hostID to string for improved logging in SyncAndCheckForHost 2026-03-01 03:56:41 +00:00
GitHub Actions
63c9976e5f fix(tests): improve login handling in navigation tests to manage transient 401 errors 2026-03-01 03:54:45 +00:00
GitHub Actions
09ef4f579e fix(tests): optimize response handling in Firefox import tests 2026-03-01 03:50:50 +00:00
GitHub Actions
fbd94a031e fix(import): handle cancellation of stale import sessions in various states 2026-03-01 03:50:43 +00:00
GitHub Actions
6483a25555 chore(tests): remove deprecated proxy host dropdown tests 2026-03-01 03:49:20 +00:00
GitHub Actions
61b73bc57b fix(tests): increase dashboard load time threshold to 8 seconds 2026-03-01 03:49:12 +00:00
GitHub Actions
d77d618de0 feat(uptime): add pending state handling for monitors; update translations and tests 2026-03-01 02:51:18 +00:00
GitHub Actions
2cd19d8964 fix(uptime): implement SyncAndCheckForHost and cleanup stale failure counts; add tests for concurrency and feature flag handling 2026-03-01 02:46:49 +00:00
GitHub Actions
61d4e12c56 fix(deps): update go.mod entries for various dependencies 2026-03-01 02:46:49 +00:00
Jeremy
5c5c1eabfc Merge branch 'development' into feature/beta-release 2026-02-28 21:02:54 -05:00
GitHub Actions
d9cc0ead71 chore: move ACL and Security Headers hotfix plan documentation to archive 2026-03-01 01:43:10 +00:00
GitHub Actions
b78798b877 chore: Update dependencies in go.sum
- Bump github.com/bytedance/sonic from v1.14.1 to v1.15.0
- Bump github.com/gabriel-vasile/mimetype from v1.4.12 to v1.4.13
- Bump github.com/glebarez/go-sqlite from v1.21.2 to v1.22.0
- Bump github.com/gin-gonic/gin from v1.11.0 to v1.12.0
- Bump github.com/google/pprof to v0.0.0-20250317173921-a4b03ec1a45e
- Bump go.opentelemetry.io/auto/sdk to v1.2.1
- Bump go.opentelemetry.io/otel to v1.40.0
- Update various other dependencies to their latest versions
2026-03-01 01:34:37 +00:00
GitHub Actions
e90ad34c28 chore: add script to update Go module dependencies 2026-03-01 01:33:26 +00:00
GitHub Actions
1a559e3c64 fix(deps): update caniuse-lite to version 1.0.30001775 2026-03-01 01:31:48 +00:00
GitHub Actions
a83967daa3 fix(deps): add new dependencies for pbkdf2, scram, stringprep, and pkcs8 2026-03-01 01:28:24 +00:00
Jeremy
e374d6f7d2 Merge pull request #778 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update dependency @types/node to ^25.3.3 (feature/beta-release)
2026-02-28 20:27:51 -05:00
renovate[bot]
7723d291ce chore(deps): update dependency @types/node to ^25.3.3 2026-03-01 01:14:16 +00:00
Jeremy
386fcd8276 Merge pull request #776 from Wikid82/feature/beta-release
Proxy Host ACL and Security Headers drop down hotfix
2026-02-28 17:33:38 -05:00
GitHub Actions
10f5e5dd1d chore: enhance coverage for AccessListSelector and ProxyHostForm components
- Added new test suite for AccessListSelector to cover token normalization and emitted values.
- Updated existing tests for AccessListSelector to handle prefixed and numeric-string form values.
- Introduced tests for ProxyHostForm to validate DNS detection, including error handling and success scenarios.
- Enhanced ProxyHostForm tests to cover token normalization for security headers and ensure proper handling of existing host values.
- Implemented additional tests for ProxyHostForm to verify domain updates based on selected containers and prompt for new base domains.
2026-02-28 21:08:16 +00:00
GitHub Actions
89281c4255 fix: add UUID validation in resolveSecurityHeaderProfileReference method 2026-02-28 21:08:16 +00:00
Jeremy
de7861abea Merge pull request #777 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update module github.com/gin-gonic/gin to v1.12.0 (feature/beta-release)
2026-02-28 09:02:53 -05:00
renovate[bot]
25443d3319 fix(deps): update module github.com/gin-gonic/gin to v1.12.0 2026-02-28 13:42:23 +00:00
GitHub Actions
be279ba864 fix: update oxc-resolver package versions to 11.19.1 in package-lock.json 2026-02-28 13:06:55 +00:00
GitHub Actions
5fe1cf9265 fix: enhance security header profile handling in ProxyHost to support UUIDs and improve form data normalization 2026-02-28 12:58:59 +00:00
GitHub Actions
cdf7948575 fix: update access list handling in ProxyHostService and forms to support access_list structure 2026-02-28 05:11:33 +00:00
GitHub Actions
b04b94e429 fix: enhance access list handling in ProxyHostHandler and forms to support string IDs 2026-02-28 05:07:24 +00:00
GitHub Actions
0ff19f66b6 fix: update resolveAccessListToken to handle accessLists and improve UUID resolution in AccessListSelector 2026-02-28 05:00:32 +00:00
GitHub Actions
bf583927c1 fix: improve ID parsing logic in AccessListSelector and ProxyHostForm to ensure valid numeric IDs 2026-02-28 04:45:26 +00:00
GitHub Actions
6ed8d8054f fix: update getOptionToken to handle string IDs correctly 2026-02-28 04:41:59 +00:00
GitHub Actions
5c4a558486 chore: enhance ACL handling in dropdowns and add emergency token flows
- Add tests to normalize string numeric ACL IDs in AccessListSelector.
- Implement regression tests for ProxyHostForm to ensure numeric ACL values are submitted correctly.
- Introduce a recovery function for ACL lockout scenarios in auth setup.
- Create new tests for ACL creation and security header profiles to ensure dropdown coverage.
- Add regression tests for ACL and Security Headers dropdown behavior in ProxyHostForm.
- Establish a security shard setup to validate emergency token configurations and reset security states.
- Enhance emergency operations tests to ensure ACL selections persist across create/edit flows.
2026-02-28 04:41:00 +00:00
GitHub Actions
2024ad1373 fix: enhance AccessListSelector and ProxyHostForm to support UUID-only options and improve token resolution 2026-02-28 03:34:54 +00:00
Jeremy
5c0185d5eb Merge branch 'development' into feature/beta-release 2026-02-27 17:13:19 -05:00
GitHub Actions
c9e4916d43 fix: update SelectContent styles to improve z-index and pointer events handling 2026-02-27 22:07:26 +00:00
GitHub Actions
75d945f706 fix: ensure ACL and Security Headers dropdown selections persist correctly in Proxy Host form 2026-02-27 21:57:05 +00:00
Jeremy
99ab2202a2 Merge pull request #774 from Wikid82/feature/beta-release
Caddy version to 2.11.1
2026-02-27 16:18:30 -05:00
GitHub Actions
feaae052ac fix: enhance SQLite error handling in global setup and TestDataManager for better diagnostics 2026-02-27 20:28:43 +00:00
GitHub Actions
476e65e7dd fix: enhance navigation error handling in Caddy import tests with retry logic 2026-02-27 18:44:43 +00:00
GitHub Actions
24a5773637 fix: implement session resume feature in Caddy import tests with mock status handling 2026-02-27 18:38:25 +00:00
Jeremy
0eb0e43d60 Merge branch 'development' into feature/beta-release 2026-02-27 13:37:55 -05:00
Jeremy
6f98962981 Merge pull request #775 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-02-27 13:37:25 -05:00
renovate[bot]
2b3b5c3ff2 fix(deps): update non-major-updates 2026-02-27 18:37:12 +00:00
GitHub Actions
eb5518092f fix: update brace-expansion package to version 5.0.4 2026-02-27 13:44:24 +00:00
GitHub Actions
1b10198d50 fix: improve import session management with enhanced cleanup and status handling 2026-02-27 13:41:26 +00:00
GitHub Actions
449d316174 fix: update fallback Caddy version to 2.11.1 in Dockerfile 2026-02-27 11:04:36 +00:00
Jeremy
9356756065 Merge pull request #772 from Wikid82/feature/beta-release
Hotfix Nightly Build
2026-02-27 05:53:23 -05:00
GitHub Actions
5b3e005f2b fix: enhance nightly build workflow with SBOM generation and fallback mechanism 2026-02-27 10:16:09 +00:00
Jeremy
7654acc710 Merge pull request #770 from Wikid82/renovate/feature/beta-release-major-7-github-artifact-actions
chore(deps): update github artifact actions to v7 (feature/beta-release) (major)
2026-02-27 05:06:32 -05:00
renovate[bot]
afb2901618 chore(deps): update github artifact actions to v7 2026-02-27 10:04:19 +00:00
Jeremy
117fd51082 Merge pull request #754 from Wikid82/feature/beta-release
Enable and test Gotify and Custom Webhook notifications
2026-02-26 22:31:53 -05:00
GitHub Actions
b66ba3ad4d fix: enhance admin onboarding tests with deterministic login navigation and improve accessibility checks in authentication flows 2026-02-27 03:05:41 +00:00
GitHub Actions
cbe238b27d fix: enforce required PR number input for manual dispatch and improve event handling in security scan workflow 2026-02-27 02:48:17 +00:00
Jeremy
f814706fe2 Merge pull request #767 from Wikid82/renovate/feature/beta-release-major-8-github-artifact-actions
chore(deps): update github artifact actions to v8 (feature/beta-release) (major)
2026-02-26 20:50:56 -05:00
renovate[bot]
fc508d01d7 chore(deps): update github artifact actions to v8 2026-02-27 01:50:32 +00:00
GitHub Actions
ba880083be fix: enhance admin onboarding tests to verify redirection and storage state after login 2026-02-27 01:23:53 +00:00
GitHub Actions
b657235870 fix: refactor Caddy import tests to use helper functions for textarea filling and upload handling 2026-02-27 00:41:54 +00:00
GitHub Actions
132b78b317 fix: remove unused readStoredAuthToken function to clean up code 2026-02-26 22:53:48 +00:00
Jeremy
25cb0528e2 Merge pull request #766 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update non-major-updates (feature/beta-release)
2026-02-26 17:52:57 -05:00
Jeremy
e9acaa61cc Merge branch 'feature/beta-release' into renovate/feature/beta-release-non-major-updates 2026-02-26 17:52:45 -05:00
GitHub Actions
218ce5658e fix: enhance Caddy import tests with improved session management and response handling 2026-02-26 22:24:48 +00:00
GitHub Actions
08a17d7716 fix: enhance admin onboarding tests with improved authentication flow and assertions 2026-02-26 21:45:21 +00:00
GitHub Actions
f9c43d50c6 fix: enhance Caddy import tests with improved authentication handling and diagnostics 2026-02-26 21:45:10 +00:00
GitHub Actions
e348b5b2a3 fix: update setSecureCookie logic for local requests and add corresponding test 2026-02-26 21:44:45 +00:00
GitHub Actions
678b442f5e fix: agent tools for improved functionality and consistency across documentation
- Updated tools for Doc_Writer, Frontend_Dev, Management, Planning, Playwright_Dev, QA_Security, and Supervisor agents to enhance terminal command execution capabilities and streamline operations.
- Removed redundant tools and ensured uniformity in tool listings across agents.
2026-02-26 21:42:37 +00:00
GitHub Actions
2470861c4a fix: update @types/node and ast-v8-to-istanbul to latest versions for improved compatibility 2026-02-26 21:33:03 +00:00
GitHub Actions
9e201126a9 fix: update @types/node to version 25.3.2 for improved type definitions 2026-02-26 21:32:32 +00:00
renovate[bot]
5b67808d13 chore(deps): update non-major-updates 2026-02-26 21:31:35 +00:00
GitHub Actions
68e3bee684 fix: enhance import tests with user authentication handling and precondition checks 2026-02-26 20:32:31 +00:00
GitHub Actions
4081003051 fix: remove adminUser parameter from cross-browser import tests for cleaner execution 2026-02-26 15:01:52 +00:00
GitHub Actions
bd2b1bd8b7 fix: enhance error handling in loginUser function for API login failures 2026-02-26 15:01:31 +00:00
GitHub Actions
5e033e4bef chore: add E2E Playwright security suite tests for Chromium, Firefox, and WebKit 2026-02-26 14:05:28 +00:00
GitHub Actions
06ba9bc438 chore: add E2E Playwright tests for Chromium and WebKit non-security shards 2026-02-26 14:02:16 +00:00
GitHub Actions
3339208e53 fix: update minimatch to versions 3.1.5 and 10.2.4 in package-lock.json 2026-02-26 14:01:51 +00:00
GitHub Actions
4fad52aef5 fix: update strip-ansi to version 7.2.0 and its dependencies 2026-02-26 14:01:33 +00:00
GitHub Actions
9664e379ea fix: update import path for TestDataManager in Caddy Import gap coverage tests 2026-02-26 07:51:30 +00:00
GitHub Actions
1e126996cb fix: Add comprehensive E2E tests for Caddy Import functionality
- Introduced `caddy-import-gaps.spec.ts` to cover identified gaps in import E2E tests, including success modal navigation, conflict details expansion, overwrite resolution flow, session resume via banner, and name editing in review.
- Added `caddy-import-webkit.spec.ts` to test WebKit-specific behaviors and edge cases, focusing on event listener attachment, async state management, form submission behavior, cookie/session storage handling, touch event handling, and large file performance.
2026-02-26 07:40:27 +00:00
GitHub Actions
f4115a2977 fix: simplify visibility checks in various test cases 2026-02-26 06:25:53 +00:00
GitHub Actions
c6fd201f90 fix: streamline setup of API mocks in cross-browser E2E tests for Caddy Import 2026-02-26 06:10:53 +00:00
GitHub Actions
6ed988dc5b fix: improve error handling and assertions in E2E tests for notifications and user management 2026-02-26 05:25:02 +00:00
Jeremy
f34a9c4f37 Merge pull request #765 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update actions/setup-go digest to 4b73464 (feature/beta-release)
2026-02-26 00:03:41 -05:00
GitHub Actions
940c42f341 fix: update workflow concurrency groups to enable run cancellation
- Refactor concurrency settings in `e2e-tests-split.yml` and `codecov-upload.yml` to remove SHA and run_id from group strings, allowing for proper cancellation of in-progress runs.
- Ensure that new pushes to the same branch cancel any ongoing workflow runs, improving CI efficiency and reducing queue times.
2026-02-26 04:53:21 +00:00
GitHub Actions
759cff5e7f fix: remove pull request trigger from container prune workflow 2026-02-26 04:47:00 +00:00
renovate[bot]
5a626715d6 chore(deps): update actions/setup-go digest to 4b73464 2026-02-26 04:46:40 +00:00
GitHub Actions
82d18f11a5 fix: restrict push branches in workflows to only main 2026-02-26 04:31:52 +00:00
GitHub Actions
fb5fdb8c4e fix: update branch triggers for CodeQL workflow to restrict pull requests and allow pushes 2026-02-26 04:20:10 +00:00
GitHub Actions
8ff3f305db fix: restrict workflows to trigger only on pushes to the main branch 2026-02-26 04:11:38 +00:00
GitHub Actions
06ceb9ef6f fix: enhance GHCR prune script to include size reporting for candidates and deleted images 2026-02-26 04:05:31 +00:00
GitHub Actions
5a3b143127 fix: remove push trigger from E2E tests workflow 2026-02-26 04:05:31 +00:00
Jeremy
d28add1a73 Merge pull request #764 from Wikid82/renovate/feature/beta-release-major-7-github-artifact-actions
chore(deps): update actions/download-artifact action to v7 (feature/beta-release)
2026-02-25 22:41:39 -05:00
renovate[bot]
70d2465429 chore(deps): update actions/download-artifact action to v7 2026-02-26 03:35:00 +00:00
Jeremy
3cc5126267 Merge pull request #763 from Wikid82/renovate/feature/beta-release-actions-attest-sbom-4.x
chore(deps): update actions/attest-sbom action to v4 (feature/beta-release)
2026-02-25 22:33:17 -05:00
Jeremy
26fde2d649 Merge branch 'feature/beta-release' into renovate/feature/beta-release-actions-attest-sbom-4.x 2026-02-25 22:33:07 -05:00
Jeremy
da2db85bfc Merge pull request #762 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-02-25 22:32:41 -05:00
renovate[bot]
ccdc719501 fix(deps): update non-major-updates 2026-02-26 03:31:33 +00:00
GitHub Actions
ac720f95df fix: implement GHCR and Docker Hub prune scripts with summary reporting 2026-02-26 03:30:02 +00:00
GitHub Actions
1913e9d739 fix: remove obsolete GHCR downloads badge script 2026-02-26 03:07:26 +00:00
renovate[bot]
a7be6c304d chore(deps): update actions/attest-sbom action to v4 2026-02-26 02:32:55 +00:00
GitHub Actions
d89b86675c chore: Add comprehensive tests for notification and permission handlers
- Implement tests for classifyProviderTestFailure function to cover various error scenarios.
- Enhance notification provider handler tests for token validation, type change rejection, and missing provider ID.
- Add tests for permission helper functions to ensure proper admin authentication checks.
- Expand coverage for utility functions in user handler and docker service tests, including error extraction and socket path handling.
- Introduce a QA report for PR #754 highlighting coverage metrics and security findings related to Gotify and webhook notifications.
2026-02-26 02:22:08 +00:00
GitHub Actions
fb69f3da12 fix: add debug output for prune script execution in container prune workflow 2026-02-25 19:50:28 +00:00
GitHub Actions
e1c0173e3d fix: update script version echo statement in prune-container-images.sh 2026-02-25 19:31:16 +00:00
GitHub Actions
46fe59cf0a fix: add GitHub CLI to tools installation in container prune workflow 2026-02-25 19:21:27 +00:00
GitHub Actions
4a398185c2 fix: remove EthicalCheck workflow due to deprecation and lack of support 2026-02-25 19:13:15 +00:00
GitHub Actions
122030269e fix: enhance API interactions by adding authorization headers and improving page reload handling 2026-02-25 19:12:43 +00:00
Jeremy
5b436a883d Merge pull request #761 from Wikid82/renovate/feature/beta-release-pin-dependencies
chore(deps): pin github/codeql-action action to 4558047 (feature/beta-release)
2026-02-25 14:07:59 -05:00
GitHub Actions
a1c88de3c4 fix: enhance GHCR API interaction by adding recommended headers and improved JSON error handling 2026-02-25 18:59:27 +00:00
GitHub Actions
a6c6ce550e fix: improve destination URL handling in HTTP wrapper to enhance security and maintain original hostname 2026-02-25 17:39:36 +00:00
GitHub Actions
1af04987e0 fix: update protected regex pattern for container pruning scripts and enhance logging details 2026-02-25 17:35:47 +00:00
GitHub Actions
ad31bacc1c fix: enhance error classification for notification provider tests and improve error messages in HTTP wrapper 2026-02-25 17:19:23 +00:00
renovate[bot]
bab8414666 chore(deps): pin github/codeql-action action to 4558047 2026-02-25 16:47:54 +00:00
GitHub Actions
0deffd37e7 fix: change default DRY_RUN value to false in prune-container-images script 2026-02-25 16:40:52 +00:00
GitHub Actions
a98c9ed311 chore: add EthicalCheck workflow for automated API security testing 2026-02-25 16:14:43 +00:00
GitHub Actions
12a04b4744 chore: update devDependencies to include ESLint plugins for CSS, JSON, and Markdown 2026-02-25 16:04:07 +00:00
Jeremy
d97c08bada Merge pull request #760 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update non-major-updates (feature/beta-release)
2026-02-25 11:03:14 -05:00
renovate[bot]
ce335ff342 chore(deps): update non-major-updates 2026-02-25 15:50:29 +00:00
GitHub Actions
cb16ac05a2 fix: implement security severity policy and enhance CodeQL checks for blocking findings 2026-02-25 15:05:41 +00:00
GitHub Actions
0917edb863 fix: enhance notification provider handling by adding token visibility logic and updating related tests 2026-02-25 12:46:11 +00:00
GitHub Actions
4d0df36e5e fix: streamline group management functions and enhance directory checks in entrypoint script 2026-02-25 12:36:19 +00:00
GitHub Actions
7b1861f5a9 fix: enhance security in account settings and notifications payload tests with API key masking and authorization headers 2026-02-25 12:15:34 +00:00
GitHub Actions
29f6664ab0 fix: enforce admin role requirement for SMTP configuration access 2026-02-25 06:29:52 +00:00
GitHub Actions
690480e181 fix: Implement user API enhancements with masked API keys and updated invite link handling 2026-02-25 06:14:03 +00:00
GitHub Actions
c156183666 fix: Enhance security handler tests and implement role-based access control
- Added role-based middleware to various security handler tests to ensure only admin users can access certain endpoints.
- Created a new test file for authorization checks on security mutators, verifying that non-admin users receive forbidden responses.
- Updated existing tests to include role setting for admin users, ensuring consistent access control during testing.
- Introduced sensitive data masking in settings handler responses, ensuring sensitive values are not exposed in API responses.
- Enhanced user handler responses to mask API keys and invite tokens, providing additional security for user-related endpoints.
- Refactored routes to group security admin endpoints under a dedicated route with role-based access control.
- Added tests for import handler routes to verify authorization guards, ensuring only admin users can access import functionalities.
2026-02-25 05:41:35 +00:00
GitHub Actions
d8e6d8d9a9 fix: update vulnerability reporting methods in SECURITY.md 2026-02-25 05:41:00 +00:00
GitHub Actions
7591d2cda8 fix: update minimum coverage threshold to 87 for frontend and backend test scripts 2026-02-25 05:39:06 +00:00
GitHub Actions
aa2e7a1685 choredocker): enhance local Docker socket access and error handling
- Added guidance for Docker socket group access in docker-compose files.
- Introduced docker-compose.override.example.yml for supplemental group configuration.
- Improved entrypoint diagnostics to include socket GID and group guidance.
- Updated README with instructions for setting up Docker socket access.
- Enhanced backend error handling to provide actionable messages for permission issues.
- Updated frontend components to display troubleshooting information regarding Docker socket access.
- Added tests to ensure proper error messages and guidance are rendered in UI.
- Revised code coverage settings to include Docker service files for better regression tracking.
2026-02-25 03:42:01 +00:00
GitHub Actions
9a683c3231 fix: enhance authentication token retrieval and header building across multiple test files 2026-02-25 02:53:10 +00:00
GitHub Actions
e5cebc091d fix: remove model references from agent markdown files 2026-02-25 02:52:28 +00:00
Jeremy
15cdaa8294 Merge pull request #759 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update non-major-updates (feature/beta-release)
2026-02-24 19:44:12 -05:00
renovate[bot]
32f2d25d58 chore(deps): update non-major-updates 2026-02-25 00:43:29 +00:00
GitHub Actions
a9dcc007e5 fix: enhance DockerUnavailableError to include detailed error messages and improve handling in ListContainers 2026-02-24 22:24:38 +00:00
GitHub Actions
bf53712b7c fix: implement bearer token handling in TestDataManager and add API helper authorization tests 2026-02-24 21:07:10 +00:00
GitHub Actions
2b4f60615f fix: add Docker socket volume for container discovery in E2E tests 2026-02-24 20:34:35 +00:00
GitHub Actions
bbaad17e97 fix: enhance notification provider validation and error handling in Test method 2026-02-24 19:56:57 +00:00
Jeremy
bc4c7c1406 Merge pull request #758 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update github/codeql-action digest to 28737ec (feature/beta-release)
2026-02-24 14:55:39 -05:00
renovate[bot]
e13b49cfd2 chore(deps): update github/codeql-action digest to 28737ec 2026-02-24 19:45:29 +00:00
GitHub Actions
4d4a5d3adb fix: update trustTestCertificate function to remove unnecessary parameter 2026-02-24 13:02:44 +00:00
GitHub Actions
7983de9f2a fix: enhance workflow triggers and context handling for security scans 2026-02-24 12:45:25 +00:00
GitHub Actions
0034968919 fix: enforce secure cookie settings and enhance URL validation in HTTP wrapper 2026-02-24 12:41:20 +00:00
GitHub Actions
6cec0a67eb fix: add exception handling for specific SSRF rule in CodeQL SARIF checks 2026-02-24 12:41:20 +00:00
GitHub Actions
f56fa41301 fix: ensure delete confirmation dialog is always open when triggered 2026-02-24 12:41:20 +00:00
GitHub Actions
b1a1a7a238 fix: enhance CodeQL SARIF parsing for improved severity level detection 2026-02-24 12:41:20 +00:00
GitHub Actions
8381790b0b fix: improve CodeQL SARIF parsing for accurate high/critical findings detection 2026-02-24 12:41:20 +00:00
GitHub Actions
65228c5ee8 fix: enhance Docker image loading and tagging in security scan workflow 2026-02-24 12:41:20 +00:00
GitHub Actions
b531a840e8 fix: refactor logout function to use useCallback for improved performance 2026-02-24 12:41:20 +00:00
GitHub Actions
5a2e11878b fix: correct configuration key from 'linters-settings' to 'settings' in golangci-lint files 2026-02-24 12:41:20 +00:00
Jeremy
fcc60a0aa3 Merge branch 'development' into feature/beta-release 2026-02-24 01:46:39 -05:00
GitHub Actions
fdbf1a66cd fix: implement outbound request URL validation and redirect guard in HTTPWrapper 2026-02-24 06:45:14 +00:00
GitHub Actions
e8a513541f fix: enhance Trivy scan result uploads with conditional checks and category tagging 2026-02-24 06:22:03 +00:00
GitHub Actions
bc9f2cf882 chore: enable Gotify and Custom Webhhok notifications and improve payload validation
- Enhanced Notifications component tests to include support for Discord, Gotify, and Webhook provider types.
- Updated test cases to validate the correct handling of provider type options and ensure proper payload structure during creation, preview, and testing.
- Introduced new tests for Gotify token handling and ensured sensitive information is not exposed in the UI.
- Refactored existing tests for clarity and maintainability, including improved assertions and error handling.
- Added comprehensive coverage for payload validation scenarios, including malformed requests and security checks against SSRF and oversized payloads.
2026-02-24 05:34:25 +00:00
Jeremy
1329b00ed5 Merge pull request #750 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update actions/download-artifact digest to 70fc10c (feature/beta-release)
2026-02-23 17:13:46 -05:00
renovate[bot]
a9c5b5b2d8 chore(deps): update actions/download-artifact digest to 70fc10c 2026-02-23 21:17:50 +00:00
Jeremy
4b9508a9be Merge pull request #741 from Wikid82/feature/beta-release
Caddy Version bump to 2.11.1
2026-02-23 16:14:36 -05:00
Jeremy
dc1426ae31 Merge pull request #749 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-02-23 15:16:07 -05:00
renovate[bot]
72bfca2dc3 fix(deps): update non-major-updates 2026-02-23 20:15:18 +00:00
GitHub Actions
09f9f7eb3d chore: remove Caddy Compatibility Gate workflow 2026-02-23 20:15:12 +00:00
GitHub Actions
9e71dd218b chore: update katex to version 0.16.33 in package-lock.json 2026-02-23 19:37:57 +00:00
GitHub Actions
ee5350d675 feat: add keepalive controls to System Settings
- Introduced optional keepalive settings: `keepalive_idle` and `keepalive_count` in the Server struct.
- Implemented UI controls for keepalive settings in System Settings, including validation and persistence.
- Added localization support for new keepalive fields in multiple languages.
- Created a manual test tracking plan for verifying keepalive controls and their behavior.
- Updated existing tests to cover new functionality and ensure proper validation of keepalive inputs.
- Ensured safe defaults and fallback behavior for missing or invalid keepalive values.
2026-02-23 19:33:56 +00:00
Jeremy
9424aca5e2 Merge pull request #748 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update github/codeql-action digest to a754a57 (feature/beta-release)
2026-02-23 09:54:55 -05:00
renovate[bot]
8fa0950138 chore(deps): update github/codeql-action digest to a754a57 2026-02-23 14:48:33 +00:00
GitHub Actions
1315d7a3ef chore: Add cache dependency path for Go setup in workflows 2026-02-23 14:41:55 +00:00
GitHub Actions
63d7c5c0c4 chore: Update Caddy patch scenario and enhance CaddyAdminAPI validation in config 2026-02-23 14:41:55 +00:00
GitHub Actions
79c8e660f5 chore: Update minimum coverage requirements to 87% for backend and frontend tests 2026-02-23 14:41:55 +00:00
GitHub Actions
7b640cc0af chore: Add Prettier and Tailwind CSS plugin to devDependencies 2026-02-23 14:41:55 +00:00
GitHub Actions
1f2b4c7d5e chore: Add Caddy compatibility gate workflow and related scripts; update documentation and test cases 2026-02-23 14:41:55 +00:00
Jeremy
441c3dc947 Merge pull request #747 from Wikid82/renovate/feature/beta-release-non-major-updates
chore(deps): update non-major-updates (feature/beta-release)
2026-02-23 09:18:31 -05:00
renovate[bot]
735b9fdd0e chore(deps): update non-major-updates 2026-02-23 14:15:17 +00:00
GitHub Actions
45458df1bf chore: Add Caddy compatibility gate workflow and related scripts; enhance SMTP settings tests 2026-02-23 13:38:02 +00:00
Jeremy
4004c6bc08 Merge pull request #743 from Wikid82/nightly
Weekly: Promote nightly to main (2026-02-23)
2026-02-23 08:08:18 -05:00
Jeremy
427babd3c1 Merge pull request #742 from Wikid82/development
Propagate changes from development into feature/beta-release
2026-02-23 08:07:28 -05:00
Jeremy
2486dc24a1 Merge pull request #739 from Wikid82/main
Propagate changes from main into development
2026-02-23 02:37:58 -05:00
Jeremy
3fa1074ea9 Merge branch 'development' into feature/beta-release 2026-02-23 02:36:39 -05:00
GitHub Actions
51d997c6fb chore: Update current spec to outline Caddy 2.11.1 compatibility, security, and UX impact plan 2026-02-23 07:31:36 +00:00
Jeremy
cdcd1b6639 Merge pull request #729 from Wikid82/feature/beta-release
Migration from Shoutrrr to Notify - Foundation
2026-02-22 21:01:44 -05:00
GitHub Actions
9634eb65ad chore: Add tests for enhanced security notification service and proxy host validation 2026-02-22 22:53:11 +00:00
GitHub Actions
a52ba29f02 chore: Update malformed URL test expectations in ProxyHostService validation 2026-02-22 17:44:17 +00:00
GitHub Actions
f5db7ad0e4 chore: Enhance backend test coverage and add new functional tests for Security page
- Added tests to `proxyhost_service_validation_test.go` to validate fallback parsing and handle invalid hostname characters.
- Introduced new tests for DNS challenge validation in `proxyhost_service_validation_test.go`.
- Updated `current_spec.md` to reflect changes in testing strategy and coverage goals for PR #729.
- Enhanced `Security.functional.test.tsx` to include navigation test for Notifications button.
- Mocked `useNavigate` from `react-router-dom` to verify navigation behavior in Security page tests.
2026-02-22 17:12:17 +00:00
GitHub Actions
7497cbecd0 chore: Implement manual test plan for SMTP mock server flakiness fix
- Added a new documentation file outlining the manual test plan to validate the SMTP mock server flakiness fix, ensuring improved mail test reliability without affecting production behavior.
- Updated the current specification document to reflect the focus on stabilizing flaky SMTP STARTTLS+AUTH unit tests, including detailed research findings and requirements for the implementation.
- Created a QA/Security validation report for the SMTP flaky test fix, confirming that changes are test-only, stable under repeated runs, and do not introduce new security risks.
2026-02-22 06:29:37 +00:00
GitHub Actions
b14f6f040f chore: Add tests for feature flags and notification providers
- Implement tests for feature flags coverage in `feature_flags_coverage_v2_test.go` to validate behavior with invalid persisted and environment values, as well as default settings.
- Create tests in `notification_provider_patch_coverage_test.go` to ensure correct handling of notification provider updates, including blocking type mutations for non-Discord providers.
- Add tests in `security_notifications_patch_coverage_test.go` to verify deprecated headers, handle invalid CIDR warnings, and ensure correct severity handling for security events.
- Introduce migration error handling tests in `routes_coverage_test.go` to ensure graceful handling of migration errors during registration.
- Enhance `cerberus_blockers_test.go` with tests for disabled security event notifications and error handling for dispatch failures.
- Update `router_test.go` to validate notify routing based on feature flags.
- Refactor `mail_service.go` to normalize base URLs for invites, ensuring proper handling of trailing slashes.
- Modify `notification_service_json_test.go` and `notification_service_test.go` to mock Discord validation and improve webhook testing.
- Update `proxyhost_service.go` to enhance hostname validation by parsing URLs.
- Refine `uptime_service.go` to extract ports correctly from URLs, including handling edge cases.
- Enhance frontend tests in `notifications.test.ts` and `Notifications.test.tsx` to ensure correct behavior for Discord notification providers and enforce type constraints.
2026-02-21 20:55:01 +00:00
GitHub Actions
89a1768496 chore: add npm update script for managing project dependencies 2026-02-21 18:06:08 +00:00
GitHub Actions
57e7aa3e81 chore(deps): update @csstools/color-helpers, @csstools/css-color-parser, and oxc-resolver to latest versions 2026-02-21 17:49:39 +00:00
Jeremy
ff88ae9fd8 Merge pull request #736 from Wikid82/renovate/feature/beta-release-goreleaser-goreleaser-action-7.x
chore(deps): update goreleaser/goreleaser-action action to v7 (feature/beta-release)
2026-02-21 12:46:37 -05:00
renovate[bot]
cddec19862 chore(deps): update goreleaser/goreleaser-action action to v7 2026-02-21 17:46:14 +00:00
Jeremy
1bbd71cac3 Merge pull request #735 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-02-21 12:43:41 -05:00
GitHub Actions
a21351cd0f chore: add CHARON_ENCRYPTION_KEY management for backend tests 2026-02-21 17:39:50 +00:00
renovate[bot]
783956cb78 fix(deps): update non-major-updates 2026-02-21 16:43:51 +00:00
GitHub Actions
9094d3b99b choret: enforce discord-only provider type across notifications API and UI
- Added validation to reject non-discord provider types in create, update, test, and preview operations.
- Updated the notifications form to automatically normalize non-discord types to discord.
- Modified UI to display explicit messaging for deprecated and non-dispatch statuses for non-discord providers.
- Enhanced tests to cover new validation logic and UI changes for provider types.
2026-02-21 14:28:06 +00:00
GitHub Actions
718358314f chore: Update notification provider to support Discord only
- Refactored notification provider tests to use Discord webhook URLs.
- Updated frontend forms and API interactions to restrict provider type to Discord.
- Modified translations to reflect the change in supported provider types.
- Enhanced UI to indicate deprecated status for non-Discord providers.
- Adjusted documentation to align with the new provider structure.
2026-02-21 06:23:46 +00:00
GitHub Actions
f11cd689a5 fix: remove legacy security notification settings and related UI components 2026-02-20 19:28:13 +00:00
Jeremy
3a3c06a5ff Merge pull request #734 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update non-major-updates (feature/beta-release)
2026-02-20 14:27:50 -05:00
renovate[bot]
c48ced8c03 fix(deps): update non-major-updates 2026-02-20 19:26:28 +00:00
GitHub Actions
4ea22c11b3 fix: package version missmatch 2026-02-20 14:21:06 +00:00
GitHub Actions
a558c36853 fix: Remove redundant entries from tools list in agent markdown files 2026-02-20 14:16:00 +00:00
GitHub Actions
1e14dcd59c fix: Prevent exposure of GotifyToken in JSON response for enhanced security 2026-02-20 14:07:21 +00:00
GitHub Actions
1d909afe41 fix: Update GotifyToken field to prevent exposure in JSON response 2026-02-20 14:06:46 +00:00
GitHub Actions
0d9ca68a94 chore: Update eslint and rollup dependencies to latest versions 2026-02-20 14:05:25 +00:00
GitHub Actions
105338ef67 fix: Sanitize event type logging in EnhancedSecurityNotificationService 2026-02-20 13:56:56 +00:00
GitHub Actions
8e88d9feae chore: Update CodeQL scan scripts and documentation for CI alignment and deprecate old suites 2026-02-20 13:55:28 +00:00
GitHub Actions
1309189523 feat: Enhance security notifications with new event types and provider integration 2026-02-20 13:03:40 +00:00
GitHub Actions
a278ae1287 chore: Enhance governance and security guidelines in documentation for GORM and token protection 2026-02-20 12:38:37 +00:00
GitHub Actions
12dd09b32b choret: Add governance guidelines for agent files and conditional GORM security scanning 2026-02-20 12:37:37 +00:00
GitHub Actions
0dfbb74c3c feat: Update security notification settings and enhance compatibility for legacy configurations 2026-02-20 05:09:03 +00:00
GitHub Actions
5429d85e8a feat: Implement enhanced security notification service with compatibility layer
- Introduced EnhancedSecurityNotificationService for provider-based notifications.
- Added migration logic from legacy notification configuration to managed providers.
- Updated NotificationConfig model to reflect API surface changes and maintain legacy fields.
- Enhanced Cerberus middleware to dispatch security events based on feature flags.
- Updated routes to utilize the new enhanced service and handle migration at startup.
- Added feature flag for security provider events to control behavior in production.
- Updated tests to cover new functionality and ensure compatibility with existing behavior.
2026-02-20 05:01:38 +00:00
GitHub Actions
82c1737d4b fix: run container as non-root user for improved security 2026-02-20 05:00:03 +00:00
GitHub Actions
1a477f90f4 chore: enhance Trivy scan script with Docker image pull and cleanup options 2026-02-20 03:12:02 +00:00
GitHub Actions
efbbf46a7a chore: update tools list in agent configurations for consistency and clarity 2026-02-20 03:11:33 +00:00
GitHub Actions
6b03ffc4bc fix: update AI model to GPT-5.3-Codex across multiple agent configurations 2026-02-20 01:49:27 +00:00
GitHub Actions
7f53c27344 chore: update .gitignore to reflect new report path and remove obsolete codecove_patch_report.md 2026-02-20 00:05:22 +00:00
GitHub Actions
127a81a748 chore: add unit test for DeprecatedUpdateSettings to verify JSON response fields 2026-02-20 00:02:48 +00:00
GitHub Actions
8f4298951a docs: update README with to make it cleaner and easier to read 2026-02-19 23:56:44 +00:00
GitHub Actions
c68804d37e feat: migrate from shoutrr to notfy 2026-02-19 22:50:05 +00:00
GitHub Actions
1189fa59b6 docs: update tools list and model versions in agent configurations 2026-02-19 16:43:08 +00:00
GitHub Actions
7070ea6f44 docs: update AI model references in agent configurations to Claude Sonnet 4.5 and 4.6 2026-02-19 16:40:53 +00:00
GitHub Actions
a3cdc70453 docs: update QA/Security Validation Report for PR1 remediation branch 2026-02-19 16:34:10 +00:00
GitHub Actions
3e2df57fd1 docs: add mandatory documentation requirements for identifying security vulnerabilities 2026-02-19 16:34:10 +00:00
GitHub Actions
2944cd6bed docs(security): add remediation options for GHSA-69x3-g4r3-p962 vulnerability 2026-02-19 16:34:10 +00:00
GitHub Actions
72c4dee12f docs(security): archive documentation for outdated supply chain vulnerability remediation strategies 2026-02-19 16:34:10 +00:00
GitHub Actions
2e85325d08 chore: update version to v0.19.0 2026-02-19 16:34:10 +00:00
GitHub Actions
e2e3cc3dcf fix: update tools list and enhance context for code review lead agent 2026-02-19 16:34:10 +00:00
GitHub Actions
5ee3ce8b0d chore: remove legacy E2E tests for security dashboard and login 2026-02-19 16:34:10 +00:00
GitHub Actions
f4ef79def3 chore: repo cleanup by archiving plans / reports 2026-02-19 16:34:10 +00:00
Jeremy
745d3afab5 Merge pull request #731 from Wikid82/renovate/feature/beta-release-non-major-updates
fix(deps): update dependency lucide-react to ^0.575.0 (feature/beta-release)
2026-02-19 11:33:07 -05:00
renovate[bot]
9a4b4632c0 fix(deps): update dependency lucide-react to ^0.575.0 2026-02-19 16:12:32 +00:00
Jeremy
28e32d5aee Merge pull request #730 from Wikid82/development
Propagate changes from development into feature/beta-release
2026-02-19 02:25:44 -05:00
Jeremy
c484e7d6d3 Merge pull request #726 from Wikid82/main
Propagate changes from main into development
2026-02-19 02:09:29 -05:00
Jeremy
7845602907 Merge pull request #725 from Wikid82/renovate/feature/beta-release-weekly-non-major-updates
fix(deps): update weekly-non-major-updates (feature/beta-release)
2026-02-18 20:26:33 -05:00
renovate[bot]
b9c1a106d5 fix(deps): update weekly-non-major-updates 2026-02-19 01:25:50 +00:00
1331 changed files with 94023 additions and 16454 deletions

View File

@@ -1,297 +0,0 @@
/**
* Security Dashboard Mobile Responsive E2E Tests
* Test IDs: MR-01 through MR-10
*
* Tests mobile viewport (375x667), tablet viewport (768x1024),
* touch targets, scrolling, and layout responsiveness.
*/
import { test, expect } from '@bgotink/playwright-coverage'
const base = process.env.CHARON_BASE_URL || 'http://localhost:8080'
test.describe('Security Dashboard Mobile (375x667)', () => {
test.use({ viewport: { width: 375, height: 667 } })
test('MR-01: cards stack vertically on mobile', async ({ page }) => {
await page.goto(`${base}/security`)
// Wait for page to load
await page.waitForSelector('[data-testid="toggle-crowdsec"]', { timeout: 10000 })
// On mobile, grid should be single column
const grid = page.locator('.grid.grid-cols-1')
await expect(grid).toBeVisible()
// Get the computed grid-template-columns
const cardsContainer = page.locator('.grid').first()
const gridStyle = await cardsContainer.evaluate((el) => {
const style = window.getComputedStyle(el)
return style.gridTemplateColumns
})
// Single column should have just one value (not multiple columns like "repeat(4, ...)")
const columns = gridStyle.split(' ').filter((s) => s.trim().length > 0)
expect(columns.length).toBeLessThanOrEqual(2) // Single column or flexible
})
test('MR-04: toggle switches have accessible touch targets', async ({ page }) => {
await page.goto(`${base}/security`)
await page.waitForSelector('[data-testid="toggle-crowdsec"]', { timeout: 10000 })
// Check CrowdSec toggle
const crowdsecToggle = page.getByTestId('toggle-crowdsec')
const crowdsecBox = await crowdsecToggle.boundingBox()
// Touch target should be at least 24px (component) + padding
// Most switches have a reasonable touch target
expect(crowdsecBox).not.toBeNull()
if (crowdsecBox) {
expect(crowdsecBox.height).toBeGreaterThanOrEqual(20)
expect(crowdsecBox.width).toBeGreaterThanOrEqual(35)
}
// Check WAF toggle
const wafToggle = page.getByTestId('toggle-waf')
const wafBox = await wafToggle.boundingBox()
expect(wafBox).not.toBeNull()
if (wafBox) {
expect(wafBox.height).toBeGreaterThanOrEqual(20)
}
})
test('MR-05: config buttons are tappable on mobile', async ({ page }) => {
await page.goto(`${base}/security`)
await page.waitForSelector('[data-testid="toggle-crowdsec"]', { timeout: 10000 })
// Find config/configure buttons
const configButtons = page.locator('button:has-text("Config"), button:has-text("Configure")')
const buttonCount = await configButtons.count()
expect(buttonCount).toBeGreaterThan(0)
// Check first config button has reasonable size
const firstButton = configButtons.first()
const box = await firstButton.boundingBox()
expect(box).not.toBeNull()
if (box) {
expect(box.height).toBeGreaterThanOrEqual(28) // Minimum tap height
}
})
test('MR-06: page content is scrollable on mobile', async ({ page }) => {
await page.goto(`${base}/security`)
await page.waitForSelector('[data-testid="toggle-crowdsec"]', { timeout: 10000 })
// Check if page is scrollable (content height > viewport)
const bodyHeight = await page.evaluate(() => document.body.scrollHeight)
const viewportHeight = 667
// If content is taller than viewport, page should scroll
if (bodyHeight > viewportHeight) {
// Attempt to scroll down
await page.evaluate(() => window.scrollBy(0, 200))
const scrollY = await page.evaluate(() => window.scrollY)
expect(scrollY).toBeGreaterThan(0)
}
})
test('MR-10: navigation is accessible on mobile', async ({ page }) => {
await page.goto(`${base}/security`)
await page.waitForSelector('[data-testid="toggle-crowdsec"]', { timeout: 10000 })
// On mobile, there should be some form of navigation
// Check if sidebar or mobile menu toggle exists
const sidebar = page.locator('nav, aside, [role="navigation"]')
const sidebarCount = await sidebar.count()
// Navigation should exist in some form
expect(sidebarCount).toBeGreaterThanOrEqual(0) // May be hidden on mobile
})
test('MR-06b: overlay renders correctly on mobile', async ({ page }) => {
await page.goto(`${base}/security`)
await page.waitForSelector('[data-testid="toggle-crowdsec"]', { timeout: 10000 })
// Skip if Cerberus is disabled (toggles would be disabled)
const cerberusDisabled = await page.locator('text=Cerberus Disabled').isVisible()
if (cerberusDisabled) {
test.skip()
return
}
// Trigger loading state by clicking a toggle
const wafToggle = page.getByTestId('toggle-waf')
const isDisabled = await wafToggle.isDisabled()
if (!isDisabled) {
await wafToggle.click()
// Check for overlay (may appear briefly)
// Use a short timeout since it might disappear quickly
try {
const overlay = page.locator('.fixed.inset-0')
await overlay.waitFor({ state: 'visible', timeout: 2000 })
// If overlay appeared, verify it fits screen
const box = await overlay.boundingBox()
if (box) {
expect(box.width).toBeLessThanOrEqual(375 + 10) // Allow small margin
}
} catch {
// Overlay might have disappeared before we could check
// This is acceptable for a fast operation
}
}
})
})
test.describe('Security Dashboard Tablet (768x1024)', () => {
test.use({ viewport: { width: 768, height: 1024 } })
test('MR-02: cards show 2 columns on tablet', async ({ page }) => {
await page.goto(`${base}/security`)
await page.waitForSelector('[data-testid="toggle-crowdsec"]', { timeout: 10000 })
// On tablet (md breakpoint), should have md:grid-cols-2
const grid = page.locator('.grid').first()
await expect(grid).toBeVisible()
// Get computed style
const gridStyle = await grid.evaluate((el) => {
const style = window.getComputedStyle(el)
return style.gridTemplateColumns
})
// Should have 2 columns at md breakpoint
const columns = gridStyle.split(' ').filter((s) => s.trim().length > 0 && s !== 'none')
expect(columns.length).toBeGreaterThanOrEqual(2)
})
test('MR-08: cards have proper spacing on tablet', async ({ page }) => {
await page.goto(`${base}/security`)
await page.waitForSelector('[data-testid="toggle-crowdsec"]', { timeout: 10000 })
// Check gap between cards
const grid = page.locator('.grid.gap-6').first()
const hasGap = await grid.isVisible()
expect(hasGap).toBe(true)
})
})
test.describe('Security Dashboard Desktop (1920x1080)', () => {
test.use({ viewport: { width: 1920, height: 1080 } })
test('MR-03: cards show 4 columns on desktop', async ({ page }) => {
await page.goto(`${base}/security`)
await page.waitForSelector('[data-testid="toggle-crowdsec"]', { timeout: 10000 })
// On desktop (lg breakpoint), should have lg:grid-cols-4
const grid = page.locator('.grid').first()
await expect(grid).toBeVisible()
// Get computed style
const gridStyle = await grid.evaluate((el) => {
const style = window.getComputedStyle(el)
return style.gridTemplateColumns
})
// Should have 4 columns at lg breakpoint
const columns = gridStyle.split(' ').filter((s) => s.trim().length > 0 && s !== 'none')
expect(columns.length).toBeGreaterThanOrEqual(4)
})
})
test.describe('Security Dashboard Layout Tests', () => {
test('cards maintain correct order across viewports', async ({ page }) => {
// Test on mobile
await page.setViewportSize({ width: 375, height: 667 })
await page.goto(`${base}/security`)
await page.waitForSelector('[data-testid="toggle-crowdsec"]', { timeout: 10000 })
// Get card headings
const getCardOrder = async () => {
const headings = await page.locator('h3').allTextContents()
return headings.filter((h) => ['CrowdSec', 'Access Control', 'Coraza', 'Rate Limiting'].includes(h))
}
const mobileOrder = await getCardOrder()
// Test on tablet
await page.setViewportSize({ width: 768, height: 1024 })
await page.waitForTimeout(100) // Allow reflow
const tabletOrder = await getCardOrder()
// Test on desktop
await page.setViewportSize({ width: 1920, height: 1080 })
await page.waitForTimeout(100) // Allow reflow
const desktopOrder = await getCardOrder()
// Order should be consistent
expect(mobileOrder).toEqual(tabletOrder)
expect(tabletOrder).toEqual(desktopOrder)
expect(desktopOrder).toEqual(['CrowdSec', 'Access Control', 'Coraza', 'Rate Limiting'])
})
test('MR-09: all security cards are visible on scroll', async ({ page }) => {
await page.setViewportSize({ width: 375, height: 667 })
await page.goto(`${base}/security`)
await page.waitForSelector('[data-testid="toggle-crowdsec"]', { timeout: 10000 })
// Scroll to each card type
const cardTypes = ['CrowdSec', 'Access Control', 'Coraza', 'Rate Limiting']
for (const cardType of cardTypes) {
const card = page.locator(`h3:has-text("${cardType}")`)
await card.scrollIntoViewIfNeeded()
await expect(card).toBeVisible()
}
})
})
test.describe('Security Dashboard Interaction Tests', () => {
test.use({ viewport: { width: 375, height: 667 } })
test('MR-07: config buttons navigate correctly on mobile', async ({ page }) => {
await page.goto(`${base}/security`)
await page.waitForSelector('[data-testid="toggle-crowdsec"]', { timeout: 10000 })
// Skip if Cerberus disabled
const cerberusDisabled = await page.locator('text=Cerberus Disabled').isVisible()
if (cerberusDisabled) {
test.skip()
return
}
// Find and click WAF Configure button
const configureButton = page.locator('button:has-text("Configure")').first()
if (await configureButton.isVisible()) {
await configureButton.click()
// Should navigate to a config page
await page.waitForTimeout(500)
const url = page.url()
// URL should include security/waf or security/rate-limiting etc
expect(url).toMatch(/security\/(waf|rate-limiting|access-lists|crowdsec)/i)
}
})
test('documentation button works on mobile', async ({ page }) => {
await page.goto(`${base}/security`)
await page.waitForSelector('[data-testid="toggle-crowdsec"]', { timeout: 10000 })
// Find documentation button
const docButton = page.locator('button:has-text("Documentation"), a:has-text("Documentation")').first()
if (await docButton.isVisible()) {
// Check it has correct external link behavior
const href = await docButton.getAttribute('href')
// Should open external docs
if (href) {
expect(href).toContain('wikid82.github.io')
}
}
})
})

View File

@@ -1,34 +0,0 @@
import { test, expect } from '@bgotink/playwright-coverage'
const base = process.env.CHARON_BASE_URL || 'http://localhost:8080'
// Hit an API route inside /api/v1 to ensure Cerberus middleware executes.
const targetPath = '/api/v1/system/my-ip'
test.describe('WAF blocking and monitoring', () => {
test('blocks malicious query when mode=block', async ({ request }) => {
// Use literal '<script>' to trigger naive WAF check
const res = await request.get(`${base}${targetPath}?<script>=x`)
expect([400, 401]).toContain(res.status())
// When WAF runs before auth, expect 400; if auth runs first, we still validate that the server rejects
if (res.status() === 400) {
const body = await res.json()
expect(body?.error).toMatch(/WAF: suspicious payload/i)
}
})
test('does not block when mode=monitor (returns 401 due to auth)', async ({ request }) => {
const res = await request.get(`${base}${targetPath}?safe=yes`)
// Unauthenticated → expect 401, not 400; proves WAF did not block
expect([401, 403]).toContain(res.status())
})
test('metrics endpoint exposes Prometheus counters', async ({ request }) => {
const res = await request.get(`${base}/metrics`)
expect(res.status()).toBe(200)
const text = await res.text()
expect(text).toContain('charon_waf_requests_total')
expect(text).toContain('charon_waf_blocked_total')
expect(text).toContain('charon_waf_monitored_total')
})
})

View File

@@ -1,26 +0,0 @@
import { test, expect } from '@bgotink/playwright-coverage'
test.describe('Login - smoke', () => {
test('renders and has no console errors on load', async ({ page }) => {
const consoleErrors: string[] = []
page.on('console', msg => {
if (msg.type() === 'error') {
consoleErrors.push(msg.text())
}
})
await page.goto('/login', { waitUntil: 'domcontentloaded' })
await expect(page).toHaveURL(/\/login(?:\?|$)/)
const emailInput = page.getByRole('textbox', { name: /email/i })
const passwordInput = page.getByLabel(/password/i)
await expect(emailInput).toBeVisible()
await expect(passwordInput).toBeVisible()
await expect(page.getByRole('button', { name: /sign in/i })).toBeVisible()
expect(consoleErrors, 'Console errors during /login load').toEqual([])
})
})

View File

@@ -94,7 +94,7 @@ Configure the application via `docker-compose.yml`:
| `CHARON_ENV` | `production` | Set to `development` for verbose logging (`CPM_ENV` supported for backward compatibility). |
| `CHARON_HTTP_PORT` | `8080` | Port for the Web UI (`CPM_HTTP_PORT` supported for backward compatibility). |
| `CHARON_DB_PATH` | `/app/data/charon.db` | Path to the SQLite database (`CPM_DB_PATH` supported for backward compatibility). |
| `CHARON_CADDY_ADMIN_API` | `http://localhost:2019` | Internal URL for Caddy API (`CPM_CADDY_ADMIN_API` supported for backward compatibility). |
| `CHARON_CADDY_ADMIN_API` | `http://localhost:2019` | Internal URL for Caddy API (`CPM_CADDY_ADMIN_API` supported for backward compatibility). Must resolve to an internal allowlisted host on port `2019`. |
| `CHARON_CADDY_CONFIG_ROOT` | `/config` | Path to Caddy autosave configuration directory. |
| `CHARON_CADDY_LOG_DIR` | `/var/log/caddy` | Directory for Caddy access logs. |
| `CHARON_CROWDSEC_LOG_DIR` | `/var/log/crowdsec` | Directory for CrowdSec logs. |
@@ -218,6 +218,8 @@ environment:
- CPM_CADDY_ADMIN_API=http://your-caddy-host:2019
```
If using a non-localhost internal hostname, add it to `CHARON_SSRF_INTERNAL_HOST_ALLOWLIST`.
**Warning**: Charon will replace Caddy's entire configuration. Backup first!
## Performance Tuning

View File

@@ -32,6 +32,8 @@ services:
#- CPM_SECURITY_RATELIMIT_ENABLED=false
#- CPM_SECURITY_ACL_ENABLED=false
- FEATURE_CERBERUS_ENABLED=true
# Docker socket group access: copy docker-compose.override.example.yml
# to docker-compose.override.yml and set your host's docker GID.
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro # For local container discovery
- crowdsec_data:/app/data/crowdsec

View File

@@ -27,6 +27,8 @@ services:
- FEATURE_CERBERUS_ENABLED=true
# Emergency "break-glass" token for security reset when ACL blocks access
- CHARON_EMERGENCY_TOKEN=03e4682c1164f0c1cb8e17c99bd1a2d9156b59824dde41af3bb67c513e5c5e92
# Docker socket group access: copy docker-compose.override.example.yml
# to docker-compose.override.yml and set your host's docker GID.
extra_hosts:
- "host.docker.internal:host-gateway"
cap_add:
@@ -45,7 +47,7 @@ services:
# - <PATH_TO_YOUR_CADDYFILE>:/import/Caddyfile:ro
# - <PATH_TO_YOUR_SITES_DIR>:/import/sites:ro # If your Caddyfile imports other files
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8080/api/v1/health || exit 1"]
test: ["CMD-SHELL", "wget -qO /dev/null http://localhost:8080/api/v1/health || exit 1"]
interval: 30s
timeout: 10s
retries: 3

View File

@@ -0,0 +1,26 @@
# Docker Compose override — copy to docker-compose.override.yml to activate.
#
# Use case: grant the container access to the host Docker socket so that
# Charon can discover running containers.
#
# 1. cp docker-compose.override.example.yml docker-compose.override.yml
# 2. Uncomment the service that matches your compose file:
# - "charon" for docker-compose.local.yml
# - "app" for docker-compose.dev.yml
# 3. Replace <GID> with the output of: stat -c '%g' /var/run/docker.sock
# 4. docker compose up -d
services:
# Uncomment for docker-compose.local.yml
charon:
group_add:
- "<GID>" # e.g. "988" — run: stat -c '%g' /var/run/docker.sock
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
# Uncomment for docker-compose.dev.yml
app:
group_add:
- "<GID>" # e.g. "988" — run: stat -c '%g' /var/run/docker.sock
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro

View File

@@ -85,8 +85,9 @@ services:
- playwright_data:/app/data
- playwright_caddy_data:/data
- playwright_caddy_config:/config
- /var/run/docker.sock:/var/run/docker.sock:ro # For container discovery in tests
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:8080/api/v1/health"]
test: ["CMD-SHELL", "wget -qO /dev/null http://localhost:8080/api/v1/health || exit 1"]
interval: 5s
timeout: 3s
retries: 12
@@ -111,6 +112,7 @@ services:
volumes:
- playwright_crowdsec_data:/var/lib/crowdsec/data
- playwright_crowdsec_config:/etc/crowdsec
- /var/run/docker.sock:/var/run/docker.sock:ro # For container discovery in tests
healthcheck:
test: ["CMD", "cscli", "version"]
interval: 10s

View File

@@ -48,9 +48,12 @@ services:
tmpfs:
# True tmpfs for E2E test data - fresh on every run, in-memory only
# mode=1777 allows any user to write (container runs as non-root)
- /app/data:size=100M,mode=1777
# 256M gives headroom for the backup service's 100MB disk-space check
- /app/data:size=256M,mode=1777
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro # For container discovery in tests
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8080/api/v1/health || exit 1"]
test: ["CMD-SHELL", "wget -qO /dev/null http://localhost:8080/api/v1/health || exit 1"]
interval: 5s
timeout: 5s
retries: 10

View File

@@ -52,7 +52,7 @@ services:
# - ./my-existing-Caddyfile:/import/Caddyfile:ro
# - ./sites:/import/sites:ro # If your Caddyfile imports other files
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8080/api/v1/health || exit 1"]
test: ["CMD-SHELL", "wget -qO /dev/null http://localhost:8080/api/v1/health || exit 1"]
interval: 30s
timeout: 10s
retries: 3

View File

@@ -27,30 +27,24 @@ get_group_by_gid() {
}
create_group_with_gid() {
local gid="$1"
local name="$2"
if command -v addgroup >/dev/null 2>&1; then
addgroup -g "$gid" "$name" 2>/dev/null || true
addgroup -g "$1" "$2" 2>/dev/null || true
return
fi
if command -v groupadd >/dev/null 2>&1; then
groupadd -g "$gid" "$name" 2>/dev/null || true
groupadd -g "$1" "$2" 2>/dev/null || true
fi
}
add_user_to_group() {
local user="$1"
local group="$2"
if command -v addgroup >/dev/null 2>&1; then
addgroup "$user" "$group" 2>/dev/null || true
addgroup "$1" "$2" 2>/dev/null || true
return
fi
if command -v usermod >/dev/null 2>&1; then
usermod -aG "$group" "$user" 2>/dev/null || true
usermod -aG "$2" "$1" 2>/dev/null || true
fi
}
@@ -142,8 +136,15 @@ if [ -S "/var/run/docker.sock" ] && is_root; then
fi
fi
elif [ -S "/var/run/docker.sock" ]; then
echo "Note: Docker socket mounted but container is running non-root; skipping docker.sock group setup."
echo " If Docker discovery is needed, run with matching group permissions (e.g., --group-add)"
DOCKER_SOCK_GID=$(stat -c '%g' /var/run/docker.sock 2>/dev/null || echo "unknown")
echo "Note: Docker socket mounted (GID=$DOCKER_SOCK_GID) but container is running non-root; skipping docker.sock group setup."
echo " If Docker discovery is needed, add 'group_add: [\"$DOCKER_SOCK_GID\"]' to your compose service."
if [ "$DOCKER_SOCK_GID" = "0" ]; then
if [ "${ALLOW_DOCKER_SOCK_GID_0:-false}" != "true" ]; then
echo "⚠️ WARNING: Docker socket GID is 0 (root group). group_add: [\"0\"] grants root-group access."
echo " Set ALLOW_DOCKER_SOCK_GID_0=true to acknowledge this risk."
fi
fi
else
echo "Note: Docker socket not found. Docker container discovery will be unavailable."
fi
@@ -191,7 +192,7 @@ if command -v cscli >/dev/null; then
echo "Initializing persistent CrowdSec configuration..."
# Check if .dist has content
if [ -d "/etc/crowdsec.dist" ] && [ -n "$(ls -A /etc/crowdsec.dist 2>/dev/null)" ]; then
if [ -d "/etc/crowdsec.dist" ] && find /etc/crowdsec.dist -mindepth 1 -maxdepth 1 -print -quit 2>/dev/null | grep -q .; then
echo "Copying config from /etc/crowdsec.dist..."
if ! cp -r /etc/crowdsec.dist/* "$CS_CONFIG_DIR/"; then
echo "ERROR: Failed to copy config from /etc/crowdsec.dist"
@@ -208,7 +209,7 @@ if command -v cscli >/dev/null; then
exit 1
fi
echo "✓ Successfully initialized config from .dist directory"
elif [ -d "/etc/crowdsec" ] && [ ! -L "/etc/crowdsec" ] && [ -n "$(ls -A /etc/crowdsec 2>/dev/null)" ]; then
elif [ -d "/etc/crowdsec" ] && [ ! -L "/etc/crowdsec" ] && find /etc/crowdsec -mindepth 1 -maxdepth 1 -print -quit 2>/dev/null | grep -q .; then
echo "Copying config from /etc/crowdsec (fallback)..."
if ! cp -r /etc/crowdsec/* "$CS_CONFIG_DIR/"; then
echo "ERROR: Failed to copy config from /etc/crowdsec (fallback)"
@@ -248,7 +249,7 @@ if command -v cscli >/dev/null; then
echo "Expected: /etc/crowdsec -> /app/data/crowdsec/config"
echo "This indicates a critical build-time issue. Symlink must be created at build time as root."
echo "DEBUG: Directory check:"
ls -la /etc/ | grep crowdsec || echo " (no crowdsec entry found)"
find /etc -mindepth 1 -maxdepth 1 -name '*crowdsec*' -exec ls -ld {} \; 2>/dev/null || echo " (no crowdsec entry found)"
exit 1
fi
@@ -302,6 +303,19 @@ ACQUIS_EOF
# Also handle case where it might be without trailing slash
sed -i 's|log_dir: /var/log$|log_dir: /var/log/crowdsec|g' "$CS_CONFIG_DIR/config.yaml"
# Redirect CrowdSec LAPI database to persistent volume
# Default path /var/lib/crowdsec/data/crowdsec.db is ephemeral (not volume-mounted),
# so it is destroyed on every container rebuild. The bouncer API key (stored on the
# persistent volume at /app/data/crowdsec/) survives rebuilds but the LAPI database
# that validates it does not — causing perpetual key rejection.
# Redirecting db_path to the volume-mounted CS_DATA_DIR fixes this.
sed -i "s|db_path: /var/lib/crowdsec/data/crowdsec.db|db_path: ${CS_DATA_DIR}/crowdsec.db|g" "$CS_CONFIG_DIR/config.yaml"
if grep -q "db_path:.*${CS_DATA_DIR}" "$CS_CONFIG_DIR/config.yaml"; then
echo "✓ CrowdSec LAPI database redirected to persistent volume: ${CS_DATA_DIR}/crowdsec.db"
else
echo "⚠️ WARNING: Could not verify LAPI db_path redirect — bouncer keys may not survive rebuilds"
fi
# Verify LAPI configuration was applied correctly
if grep -q "listen_uri:.*:8085" "$CS_CONFIG_DIR/config.yaml"; then
echo "✓ CrowdSec LAPI configured for port 8085"
@@ -309,10 +323,11 @@ ACQUIS_EOF
echo "✗ WARNING: LAPI port configuration may be incorrect"
fi
# Update hub index to ensure CrowdSec can start
if [ ! -f "/etc/crowdsec/hub/.index.json" ]; then
echo "Updating CrowdSec hub index..."
timeout 60s cscli hub update 2>/dev/null || echo "⚠️ Hub update timed out or failed, continuing..."
# Always refresh hub index on startup (stale index causes hash mismatch errors on collection install)
echo "Updating CrowdSec hub index..."
if ! timeout 60s cscli hub update 2>&1; then
echo "⚠️ Hub index update failed (network issue?). Collections may fail to install."
echo " CrowdSec will still start with whatever index is cached."
fi
# Ensure local machine is registered (auto-heal for volume/config mismatch)
@@ -320,12 +335,11 @@ ACQUIS_EOF
echo "Registering local machine..."
cscli machines add -a --force 2>/dev/null || echo "Warning: Machine registration may have failed"
# Install hub items (parsers, scenarios, collections) if local mode enabled
if [ "$SECURITY_CROWDSEC_MODE" = "local" ]; then
echo "Installing CrowdSec hub items..."
if [ -x /usr/local/bin/install_hub_items.sh ]; then
/usr/local/bin/install_hub_items.sh 2>/dev/null || echo "Warning: Some hub items may not have installed"
fi
# Always ensure required collections are present (idempotent — already-installed items are skipped).
# Collections are just config files with zero runtime cost when CrowdSec is disabled.
echo "Ensuring CrowdSec hub items are installed..."
if [ -x /usr/local/bin/install_hub_items.sh ]; then
/usr/local/bin/install_hub_items.sh || echo "⚠️ Some hub items may not have installed. CrowdSec can still start."
fi
# Fix ownership AFTER cscli commands (they run as root and create root-owned files)
@@ -364,7 +378,7 @@ echo "Caddy started (PID: $CADDY_PID)"
echo "Waiting for Caddy admin API..."
i=1
while [ "$i" -le 30 ]; do
if curl -sf http://127.0.0.1:2019/config/ > /dev/null 2>&1; then
if wget -qO /dev/null http://127.0.0.1:2019/config/ 2>/dev/null; then
echo "Caddy is ready!"
break
fi

View File

@@ -9,13 +9,12 @@
.git/
.gitignore
.github/
.pre-commit-config.yaml
codecov.yml
.goreleaser.yaml
.sourcery.yml
# -----------------------------------------------------------------------------
# Python (pre-commit, tooling)
# Python (tooling)
# -----------------------------------------------------------------------------
__pycache__/
*.py[cod]

View File

@@ -2,9 +2,10 @@
name: 'Backend Dev'
description: 'Senior Go Engineer focused on high-performance, secure backend implementation.'
argument-hint: 'The specific backend task from the Plan (e.g., "Implement ProxyHost CRUD endpoints")'
tools: vscode/extensions, vscode/getProjectSetupInfo, vscode/installExtension, vscode/memory, vscode/openSimpleBrowser, vscode/runCommand, vscode/askQuestions, vscode/vscodeAPI, execute, read, agent, 'github/*', 'github/*', 'io.github.goreleaser/mcp/*', 'trivy-mcp/*', edit, search, web, 'github/*', 'playwright/*', 'pylance-mcp-server/*', todo, vscode.mermaid-chat-features/renderMermaidDiagram, github.vscode-pull-request-github/issue_fetch, github.vscode-pull-request-github/labels_fetch, github.vscode-pull-request-github/notification_fetch, github.vscode-pull-request-github/doSearch, github.vscode-pull-request-github/activePullRequest, github.vscode-pull-request-github/openPullRequest, ms-azuretools.vscode-containers/containerToolsConfig, ms-python.python/getPythonEnvironmentInfo, ms-python.python/getPythonExecutableCommand, ms-python.python/installPythonPackage, ms-python.python/configurePythonEnvironment, 'gopls/*'
tools: vscode/getProjectSetupInfo, vscode/installExtension, vscode/memory, vscode/runCommand, vscode/vscodeAPI, vscode/extensions, vscode/askQuestions, execute, read, edit, search, web, browser, github/add_comment_to_pending_review, github/add_issue_comment, github/add_reply_to_pull_request_comment, github/assign_copilot_to_issue, github/create_branch, github/create_or_update_file, github/create_pull_request, github/create_pull_request_with_copilot, github/create_repository, github/delete_file, github/fork_repository, github/get_commit, github/get_copilot_job_status, github/get_file_contents, github/get_label, github/get_latest_release, github/get_me, github/get_release_by_tag, github/get_tag, github/get_team_members, github/get_teams, github/issue_read, github/issue_write, github/list_branches, github/list_commits, github/list_issue_types, github/list_issues, github/list_pull_requests, github/list_releases, github/list_tags, github/merge_pull_request, github/pull_request_read, github/pull_request_review_write, github/push_files, github/request_copilot_review, github/search_code, github/search_issues, github/search_pull_requests, github/search_repositories, github/search_users, github/sub_issue_write, github/update_pull_request, github/update_pull_request_branch, playwright/*, github/*, io.github.goreleaser/mcp/*, mcp-refactor-typescript/*, microsoftdocs/mcp/*, vscode.mermaid-chat-features/renderMermaidDiagram, github.vscode-pull-request-github/issue_fetch, github.vscode-pull-request-github/labels_fetch, github.vscode-pull-request-github/notification_fetch, github.vscode-pull-request-github/doSearch, github.vscode-pull-request-github/activePullRequest, github.vscode-pull-request-github/pullRequestStatusChecks, github.vscode-pull-request-github/openPullRequest, ms-azuretools.vscode-containers/containerToolsConfig, ms-python.python/getPythonEnvironmentInfo, ms-python.python/getPythonExecutableCommand, ms-python.python/installPythonPackage, ms-python.python/configurePythonEnvironment, todo
model: GPT-5.3-Codex (copilot)
target: vscode
user-invocable: true
disable-model-invocation: false
@@ -15,6 +16,9 @@ Your priority is writing code that is clean, tested, and secure by default.
<context>
- **Governance**: When this agent file conflicts with canonical instruction
files (`.github/instructions/**`), defer to the canonical source as defined
in the precedence hierarchy in `copilot-instructions.md`.
- **MANDATORY**: Read all relevant instructions in `.github/instructions/` for the specific task before starting.
- **Project**: Charon (Self-hosted Reverse Proxy)
- **Stack**: Go 1.22+, Gin, GORM, SQLite.
@@ -41,14 +45,21 @@ Your priority is writing code that is clean, tested, and secure by default.
- Define the structs in `internal/models` to fix compilation errors.
- **Step 3 (The Logic)**:
- Implement the handler in `internal/api/handlers`.
- **Step 4 (The Green Light)**:
- **Step 4 (Lint and Format)**:
- Run `lefthook run pre-commit` to ensure code quality.
- **Step 5 (The Green Light)**:
- Run `go test ./...`.
- **CRITICAL**: If it fails, fix the *Code*, NOT the *Test* (unless the test was wrong about the contract).
3. **Verification (Definition of Done)**:
- Run `go mod tidy`.
- Run `go fmt ./...`.
- Run `go test ./...` to ensure no regressions.
- Run `go test ./...` to ensure no regressions.
- **Conditional GORM Gate**: If task changes include model/database-related
files (`backend/internal/models/**`, GORM query logic, migrations), run
GORM scanner in check mode and treat CRITICAL/HIGH findings as blocking:
- Run: `lefthook run pre-commit` (which includes manual gorm-security-scan) OR `./scripts/scan-gorm-security.sh --check`
- Policy: Process-blocking gate even while automation is manual stage
- **Local Patch Coverage Preflight (MANDATORY)**: Run VS Code task `Test: Local Patch Report` or `bash scripts/local-patch-report.sh` before backend coverage runs.
- Ensure artifacts exist: `test-results/local-patch-report.md` and `test-results/local-patch-report.json`.
- Use the file-level coverage gap list to target tests before final coverage validation.
@@ -58,9 +69,9 @@ Your priority is writing code that is clean, tested, and secure by default.
- **Manual Script**: Execute `/projects/Charon/scripts/go-test-coverage.sh` from the root directory
- **Minimum**: 85% coverage (configured via `CHARON_MIN_COVERAGE` or `CPM_MIN_COVERAGE`)
- **Critical**: If coverage drops below threshold, write additional tests immediately. Do not skip this step.
- **Why**: Coverage tests are in manual stage of pre-commit for performance. You MUST run them via VS Code tasks or scripts before completing your task.
- **Why**: Coverage tests are in manual stage of lefthook for performance. You MUST run them via VS Code tasks or scripts before completing your task.
- Ensure coverage goals are met as well as all tests pass. Just because Tests pass does not mean you are done. Goal Coverage Needs to be met even if the tests to get us there are outside the scope of your task. At this point, your task is to maintain coverage goal and all tests pass because we cannot commit changes if they fail.
- Run `pre-commit run --all-files` as final check (this runs fast hooks only; coverage was verified above).
- Run `lefthook run pre-commit` as final check (this runs fast hooks only; coverage was verified above).
</workflow>
<constraints>

View File

@@ -2,9 +2,9 @@
name: 'DevOps'
description: 'DevOps specialist for CI/CD pipelines, deployment debugging, and GitOps workflows focused on making deployments boring and reliable'
argument-hint: 'The CI/CD or infrastructure task (e.g., "Debug failing GitHub Action workflow")'
tools: vscode/extensions, vscode/getProjectSetupInfo, vscode/installExtension, vscode/memory, vscode/openSimpleBrowser, vscode/runCommand, vscode/askQuestions, vscode/vscodeAPI, execute, read, agent, 'github/*', 'github/*', 'io.github.goreleaser/mcp/*', 'trivy-mcp/*', edit, search, web, 'github/*', 'playwright/*', 'pylance-mcp-server/*', todo, vscode.mermaid-chat-features/renderMermaidDiagram, github.vscode-pull-request-github/issue_fetch, github.vscode-pull-request-github/labels_fetch, github.vscode-pull-request-github/notification_fetch, github.vscode-pull-request-github/doSearch, github.vscode-pull-request-github/activePullRequest, github.vscode-pull-request-github/openPullRequest, ms-azuretools.vscode-containers/containerToolsConfig, ms-python.python/getPythonEnvironmentInfo, ms-python.python/getPythonExecutableCommand, ms-python.python/installPythonPackage, ms-python.python/configurePythonEnvironment, 'gopls/*'
tools: vscode/getProjectSetupInfo, vscode/installExtension, vscode/memory, vscode/runCommand, vscode/vscodeAPI, vscode/extensions, vscode/askQuestions, execute, read, edit, search, web, browser, github/add_comment_to_pending_review, github/add_issue_comment, github/add_reply_to_pull_request_comment, github/assign_copilot_to_issue, github/create_branch, github/create_or_update_file, github/create_pull_request, github/create_pull_request_with_copilot, github/create_repository, github/delete_file, github/fork_repository, github/get_commit, github/get_copilot_job_status, github/get_file_contents, github/get_label, github/get_latest_release, github/get_me, github/get_release_by_tag, github/get_tag, github/get_team_members, github/get_teams, github/issue_read, github/issue_write, github/list_branches, github/list_commits, github/list_issue_types, github/list_issues, github/list_pull_requests, github/list_releases, github/list_tags, github/merge_pull_request, github/pull_request_read, github/pull_request_review_write, github/push_files, github/request_copilot_review, github/search_code, github/search_issues, github/search_pull_requests, github/search_repositories, github/search_users, github/sub_issue_write, github/update_pull_request, github/update_pull_request_branch, playwright/*, github/*, io.github.goreleaser/mcp/*, mcp-refactor-typescript/*, microsoftdocs/mcp/*, vscode.mermaid-chat-features/renderMermaidDiagram, github.vscode-pull-request-github/issue_fetch, github.vscode-pull-request-github/labels_fetch, github.vscode-pull-request-github/notification_fetch, github.vscode-pull-request-github/doSearch, github.vscode-pull-request-github/activePullRequest, github.vscode-pull-request-github/pullRequestStatusChecks, github.vscode-pull-request-github/openPullRequest, ms-azuretools.vscode-containers/containerToolsConfig, ms-python.python/getPythonEnvironmentInfo, ms-python.python/getPythonExecutableCommand, ms-python.python/installPythonPackage, ms-python.python/configurePythonEnvironment, todo
model: GPT-5.3-Codex (copilot)
target: vscode
user-invocable: true
disable-model-invocation: false

View File

@@ -2,9 +2,9 @@
name: 'Docs Writer'
description: 'User Advocate and Writer focused on creating simple, layman-friendly documentation.'
argument-hint: 'The feature to document (e.g., "Write the guide for the new Real-Time Logs")'
tools: vscode/extensions, vscode/getProjectSetupInfo, vscode/installExtension, vscode/memory, vscode/openSimpleBrowser, vscode/runCommand, vscode/askQuestions, vscode/vscodeAPI, execute, read, agent, 'github/*', 'github/*', 'io.github.goreleaser/mcp/*', 'trivy-mcp/*', edit, search, web, 'github/*', 'playwright/*', 'pylance-mcp-server/*', todo, vscode.mermaid-chat-features/renderMermaidDiagram, github.vscode-pull-request-github/issue_fetch, github.vscode-pull-request-github/labels_fetch, github.vscode-pull-request-github/notification_fetch, github.vscode-pull-request-github/doSearch, github.vscode-pull-request-github/activePullRequest, github.vscode-pull-request-github/openPullRequest, ms-azuretools.vscode-containers/containerToolsConfig, ms-python.python/getPythonEnvironmentInfo, ms-python.python/getPythonExecutableCommand, ms-python.python/installPythonPackage, ms-python.python/configurePythonEnvironment, 'gopls/*'
tools: vscode/getProjectSetupInfo, vscode/installExtension, vscode/memory, vscode/runCommand, vscode/vscodeAPI, vscode/extensions, vscode/askQuestions, execute, read, edit, search, web, browser, github/add_comment_to_pending_review, github/add_issue_comment, github/add_reply_to_pull_request_comment, github/assign_copilot_to_issue, github/create_branch, github/create_or_update_file, github/create_pull_request, github/create_pull_request_with_copilot, github/create_repository, github/delete_file, github/fork_repository, github/get_commit, github/get_copilot_job_status, github/get_file_contents, github/get_label, github/get_latest_release, github/get_me, github/get_release_by_tag, github/get_tag, github/get_team_members, github/get_teams, github/issue_read, github/issue_write, github/list_branches, github/list_commits, github/list_issue_types, github/list_issues, github/list_pull_requests, github/list_releases, github/list_tags, github/merge_pull_request, github/pull_request_read, github/pull_request_review_write, github/push_files, github/request_copilot_review, github/search_code, github/search_issues, github/search_pull_requests, github/search_repositories, github/search_users, github/sub_issue_write, github/update_pull_request, github/update_pull_request_branch, playwright/*, github/*, io.github.goreleaser/mcp/*, mcp-refactor-typescript/*, microsoftdocs/mcp/*, vscode.mermaid-chat-features/renderMermaidDiagram, github.vscode-pull-request-github/issue_fetch, github.vscode-pull-request-github/labels_fetch, github.vscode-pull-request-github/notification_fetch, github.vscode-pull-request-github/doSearch, github.vscode-pull-request-github/activePullRequest, github.vscode-pull-request-github/pullRequestStatusChecks, github.vscode-pull-request-github/openPullRequest, ms-azuretools.vscode-containers/containerToolsConfig, ms-python.python/getPythonEnvironmentInfo, ms-python.python/getPythonExecutableCommand, ms-python.python/installPythonPackage, ms-python.python/configurePythonEnvironment, todo
model: GPT-5.3-Codex (copilot)
target: vscode
user-invocable: true
disable-model-invocation: false

View File

@@ -2,9 +2,10 @@
name: 'Frontend Dev'
description: 'Senior React/TypeScript Engineer for frontend implementation.'
argument-hint: 'The frontend feature or component to implement (e.g., "Implement the Real-Time Logs dashboard component")'
tools: vscode/extensions, vscode/getProjectSetupInfo, vscode/installExtension, vscode/memory, vscode/openSimpleBrowser, vscode/runCommand, vscode/askQuestions, vscode/vscodeAPI, execute, read, agent, 'github/*', 'github/*', 'io.github.goreleaser/mcp/*', 'trivy-mcp/*', edit, search, web, 'github/*', 'playwright/*', 'pylance-mcp-server/*', todo, vscode.mermaid-chat-features/renderMermaidDiagram, github.vscode-pull-request-github/issue_fetch, github.vscode-pull-request-github/labels_fetch, github.vscode-pull-request-github/notification_fetch, github.vscode-pull-request-github/doSearch, github.vscode-pull-request-github/activePullRequest, github.vscode-pull-request-github/openPullRequest, ms-azuretools.vscode-containers/containerToolsConfig, ms-python.python/getPythonEnvironmentInfo, ms-python.python/getPythonExecutableCommand, ms-python.python/installPythonPackage, ms-python.python/configurePythonEnvironment, 'gopls/*'
tools: vscode/getProjectSetupInfo, vscode/installExtension, vscode/memory, vscode/runCommand, vscode/vscodeAPI, vscode/extensions, vscode/askQuestions, execute, read, edit, search, web, browser, github/add_comment_to_pending_review, github/add_issue_comment, github/add_reply_to_pull_request_comment, github/assign_copilot_to_issue, github/create_branch, github/create_or_update_file, github/create_pull_request, github/create_pull_request_with_copilot, github/create_repository, github/delete_file, github/fork_repository, github/get_commit, github/get_copilot_job_status, github/get_file_contents, github/get_label, github/get_latest_release, github/get_me, github/get_release_by_tag, github/get_tag, github/get_team_members, github/get_teams, github/issue_read, github/issue_write, github/list_branches, github/list_commits, github/list_issue_types, github/list_issues, github/list_pull_requests, github/list_releases, github/list_tags, github/merge_pull_request, github/pull_request_read, github/pull_request_review_write, github/push_files, github/request_copilot_review, github/search_code, github/search_issues, github/search_pull_requests, github/search_repositories, github/search_users, github/sub_issue_write, github/update_pull_request, github/update_pull_request_branch, playwright/*, github/*, io.github.goreleaser/mcp/*, mcp-refactor-typescript/*, microsoftdocs/mcp/*, vscode.mermaid-chat-features/renderMermaidDiagram, github.vscode-pull-request-github/issue_fetch, github.vscode-pull-request-github/labels_fetch, github.vscode-pull-request-github/notification_fetch, github.vscode-pull-request-github/doSearch, github.vscode-pull-request-github/activePullRequest, github.vscode-pull-request-github/pullRequestStatusChecks, github.vscode-pull-request-github/openPullRequest, ms-azuretools.vscode-containers/containerToolsConfig, ms-python.python/getPythonEnvironmentInfo, ms-python.python/getPythonExecutableCommand, ms-python.python/installPythonPackage, ms-python.python/configurePythonEnvironment, todo
model: GPT-5.3-Codex (copilot)
target: vscode
user-invocable: true
disable-model-invocation: false
@@ -48,8 +49,7 @@ You are a SENIOR REACT/TYPESCRIPT ENGINEER with deep expertise in:
- Run tests with `npm test` in `frontend/` directory
4. **Quality Checks**:
- Run `npm run lint` to check for linting issues
- Run `npm run typecheck` for TypeScript errors
- Run `lefthook run pre-commit` to ensure linting and formatting
- Ensure accessibility with proper ARIA attributes
</workflow>

View File

@@ -3,9 +3,9 @@ name: 'Management'
description: 'Engineering Director. Delegates ALL research and execution. DO NOT ask it to debug code directly.'
argument-hint: 'The high-level goal (e.g., "Build the new Proxy Host Dashboard widget")'
tools: vscode/extensions, vscode/getProjectSetupInfo, vscode/installExtension, vscode/memory, vscode/openIntegratedBrowser, vscode/runCommand, vscode/askQuestions, vscode/vscodeAPI, execute, read, agent, 'github/*', 'github/*', 'io.github.goreleaser/mcp/*', 'trivy-mcp/*', edit, search, web, 'github/*', 'gopls/*', 'playwright/*', 'pylance-mcp-server/*', todo, vscode.mermaid-chat-features/renderMermaidDiagram, github.vscode-pull-request-github/issue_fetch, github.vscode-pull-request-github/labels_fetch, github.vscode-pull-request-github/notification_fetch, github.vscode-pull-request-github/doSearch, github.vscode-pull-request-github/activePullRequest, github.vscode-pull-request-github/openPullRequest, ms-azuretools.vscode-containers/containerToolsConfig, ms-python.python/getPythonEnvironmentInfo, ms-python.python/getPythonExecutableCommand, ms-python.python/installPythonPackage, ms-python.python/configurePythonEnvironment
tools: vscode/extensions, vscode/getProjectSetupInfo, vscode/installExtension, vscode/memory, vscode/runCommand, vscode/vscodeAPI, vscode/askQuestions, execute, read, agent, edit, search, web, 'github/*', 'playwright/*', 'github/*', 'github/*', 'io.github.goreleaser/mcp/*', 'mcp-refactor-typescript/*', 'microsoftdocs/mcp/*', browser, vscode.mermaid-chat-features/renderMermaidDiagram, github.vscode-pull-request-github/issue_fetch, github.vscode-pull-request-github/labels_fetch, github.vscode-pull-request-github/notification_fetch, github.vscode-pull-request-github/doSearch, github.vscode-pull-request-github/activePullRequest, github.vscode-pull-request-github/pullRequestStatusChecks, github.vscode-pull-request-github/openPullRequest, ms-azuretools.vscode-containers/containerToolsConfig, ms-python.python/getPythonEnvironmentInfo, ms-python.python/getPythonExecutableCommand, ms-python.python/installPythonPackage, ms-python.python/configurePythonEnvironment, todo
model: GPT-5.3-Codex (copilot)
target: vscode
user-invocable: true
disable-model-invocation: false
@@ -18,19 +18,22 @@ You are "lazy" in the smartest way possible. You never do what a subordinate can
1. **Initialize**: ALWAYS read `.github/instructions/copilot-instructions.md` first to load global project rules.
2. **MANDATORY**: Read all relevant instructions in `.github/instructions/**` for the specific task before starting.
3. **Team Roster**:
3. **Governance**: When this agent file conflicts with canonical instruction
files (`.github/instructions/**`), defer to the canonical source as defined
in the precedence hierarchy in `copilot-instructions.md`.
4. **Team Roster**:
- `Planning`: The Architect. (Delegate research & planning here).
- `Supervisor`: The Senior Advisor. (Delegate plan review here).
- `Backend_Dev`: The Engineer. (Delegate Go implementation here).
- `Frontend_Dev`: The Designer. (Delegate React implementation here).
- `QA_Security`: The Auditor. (Delegate verification and testing here).
- `Docs_Writer`: The Scribe. (Delegate docs here).
- `Backend Dev`: The Engineer. (Delegate Go implementation here).
- `Frontend Dev`: The Designer. (Delegate React implementation here).
- `QA Security`: The Auditor. (Delegate verification and testing here).
- `Docs Writer`: The Scribe. (Delegate docs here).
- `DevOps`: The Packager. (Delegate CI/CD and infrastructure here).
- `Playwright_Dev`: The E2E Specialist. (Delegate Playwright test creation and maintenance here).
4. **Parallel Execution**:
- `Playwright Dev`: The E2E Specialist. (Delegate Playwright test creation and maintenance here).
5. **Parallel Execution**:
- You may delegate to `runSubagent` multiple times in parallel if tasks are independent. The only exception is `QA_Security`, which must run last as this validates the entire codebase after all changes.
5. **Implementation Choices**:
- When faced with multiple implementation options, ALWAYS choose the "Prroper" fix over a "Quick" fix. This ensures long-term maintainability and saves double work. The "Quick" fix will only cause more work later when the "Proper" fix is eventually needed.
6. **Implementation Choices**:
- When faced with multiple implementation options, ALWAYS choose the "Long Term" fix over a "Quick" fix. This ensures long-term maintainability and saves double work. The "Quick" fix will only cause more work later when the "Long Term" fix is eventually needed.
</global_context>
<workflow>
@@ -40,7 +43,7 @@ You are "lazy" in the smartest way possible. You never do what a subordinate can
- **Identify Goal**: Understand the user's request.
- **STOP**: Do not look at the code. Do not run `list_dir`. No code is to be changed or implemented until there is a fundamentally sound plan of action that has been approved by the user.
- **Action**: Immediately call `Planning` subagent.
- *Prompt*: "Research the necessary files for '{user_request}' and write a comprehensive plan detailing as many specifics as possible to `docs/plans/current_spec.md`. Be an artist with directions and discriptions. Include file names, function names, and component names wherever possible. Break the plan into phases based on the least amount of requests. Include a PR Slicing Strategy section that decides whether to split work into multiple PRs and, when split, defines PR-1/PR-2/PR-3 scope, dependencies, and acceptance criteria. Review and suggest updaetes to `.gitignore`, `codecov.yml`, `.dockerignore`, and `Dockerfile` if necessary. Return only when the plan is complete."
- *Prompt*: "Research the necessary files for '{user_request}' and write a comprehensive plan detailing as many specifics as possible to `docs/plans/current_spec.md`. Be an artist with directions and discriptions. Include file names, function names, and component names wherever possible. Break the plan into phases based on the least amount of requests. Include a Commit Slicing Strategy section that organizes work into logical commits within a single PR — one feature = one PR, with ordered commits (Commit 1, Commit 2, …) each defining scope, files, dependencies, and validation gates. Review and suggest updaetes to `.gitignore`, `codecov.yml`, `.dockerignore`, and `Dockerfile` if necessary. Return only when the plan is complete."
- **Task Specifics**:
- If the task is to just run tests or audits, there is no need for a plan. Directly call `QA_Security` to perform the tests and write the report. If issues are found, return to `Planning` for a remediation plan and delegate the fixes to the corresponding subagents.
@@ -56,26 +59,26 @@ You are "lazy" in the smartest way possible. You never do what a subordinate can
- **Ask**: "Plan created. Shall I authorize the construction?"
4. **Phase 4: Execution (Waterfall)**:
- **Single-PR or Multi-PR Decision**: Read the PR Slicing Strategy in `docs/plans/current_spec.md`.
- **If single PR**:
- **Read Commit Slicing Strategy**: Read the Commit Slicing Strategy in `docs/plans/current_spec.md` to understand the ordered commits.
- **Single PR, Multiple Commits**: All work ships as one PR. Each commit maps to a phase in the plan.
- **Backend**: Call `Backend_Dev` with the plan file.
- **Frontend**: Call `Frontend_Dev` with the plan file.
- **If multi-PR**:
- Execute in PR slices, one slice at a time, in dependency order.
- Require each slice to pass review + QA gates before starting the next slice.
- Keep every slice deployable and independently testable.
- Execute commits in dependency order. Each commit must pass its validation gates before the next commit begins.
- The PR is merged only when all commits are complete and all DoD gates pass.
- **MANDATORY**: Implementation agents must perform linting and type checks locally before declaring their commit "DONE". This is a critical step that must not be skipped to avoid broken commits and security issues.
5. **Phase 5: Review**:
- **Supervisor**: Call `Supervisor` to review the implementation against the plan. Provide feedback and ensure alignment with best practices.
6. **Phase 6: Audit**:
- **QA**: Call `QA_Security` to meticulously test current implementation as well as regression test. Run all linting, security tasks, and manual pre-commit checks. Write a report to `docs/reports/qa_report.md`. Start back at Phase 1 if issues are found.
- Review Security: Read `security.md.instrutctions.md` and `SECURITY.md` to understand the security requirements and best practices for Charon. Ensure that any open concerns or issues are addressed in the QA Audit and `SECURITY.md` is updated accordingly.
- **QA**: Call `QA_Security` to meticulously test current implementation as well as regression test. Run all linting, security tasks, and manual lefthook checks. Write a report to `docs/reports/qa_report.md`. Start back at Phase 1 if issues are found.
7. **Phase 7: Closure**:
- **Docs**: Call `Docs_Writer`.
- **Manual Testing**: create a new test plan in `docs/issues/*.md` for tracking manual testing focused on finding potential bugs of the implemented features.
- **Final Report**: Summarize the successful subagent runs.
- **PR Roadmap**: If split mode was used, include a concise roadmap of completed and remaining PR slices.
- **Commit Roadmap**: Include a concise summary of completed and remaining commits within the PR.
**Mandatory Commit Message**: When you reach a stopping point, provide a copy and paste code block commit message at the END of the response on format laid out in `.github/instructions/commit-message.instructions.md`
- **STRICT RULES**:
@@ -145,6 +148,16 @@ The task is not complete until ALL of the following pass with zero issues:
```
This ensures the container has latest code and proper environment variables (emergency token, encryption key from `.env`).
- **Run**: `npx playwright test --project=chromium --project=firefox --project=webkit` from project root
1.5. **GORM Security Scan (Conditional Gate)**:
- **Delegation Verification:** If implementation touched backend models
(`backend/internal/models/**`) or database-interaction paths
(GORM services, migrations), confirm `QA_Security` (or responsible
subagent) ran the GORM scanner using check mode (`--check`) and resolved
all CRITICAL/HIGH findings before accepting task completion
- **Manual Stage Clarification:** Scanner execution is manual
(not automated pre-commit), but enforcement is process-blocking for DoD
when triggered
- **No Truncation**: Never pipe output through `head`, `tail`, or other truncating commands. Playwright requires user input to quit when piped, causing hangs.
- **Why First**: If the app is broken at E2E level, unit tests may need updates. Catch integration issues early.
- **Scope**: Run tests relevant to modified features (e.g., `tests/manual-dns-provider.spec.ts`)
@@ -152,23 +165,27 @@ The task is not complete until ALL of the following pass with zero issues:
- **Base URL**: Uses `PLAYWRIGHT_BASE_URL` or default from `playwright.config.js`
- All E2E tests must pass before proceeding to unit tests
2. **Local Patch Coverage Preflight (MANDATORY - Before Unit/Coverage Tests)**:
- Ensure the local patch report is run first via VS Code task `Test: Local Patch Report` or `bash scripts/local-patch-report.sh`.
- Verify both artifacts exist: `test-results/local-patch-report.md` and `test-results/local-patch-report.json`.
- Use this report to identify changed files needing coverage before running backend/frontend coverage suites.
3. **Coverage Tests (MANDATORY - Verify Explicitly)**:
2. **Coverage Tests (MANDATORY - Verify Explicitly)**:
- **Backend**: Ensure `Backend_Dev` ran VS Code task "Test: Backend with Coverage" or `scripts/go-test-coverage.sh`
- **Frontend**: Ensure `Frontend_Dev` ran VS Code task "Test: Frontend with Coverage" or `scripts/frontend-test-coverage.sh`
- **Why**: These are in manual stage of pre-commit for performance. Subagents MUST run them via VS Code tasks or scripts.
- Minimum coverage: 85% for both backend and frontend.
- All tests must pass with zero failures.
- **Outputs**: `backend/coverage.txt` and `frontend/coverage/lcov.info` — these are required inputs for step 3.
3. **Local Patch Coverage Report (MANDATORY - After Coverage Tests)**:
- **Purpose**: Identify uncovered lines in files modified by this task so missing tests are written before declaring Done. This is the bridge between "overall coverage is fine" and "the actual lines I changed are tested."
- **Prerequisites**: `backend/coverage.txt` and `frontend/coverage/lcov.info` must exist (generated by step 2). If missing, run coverage tests first.
- **Run**: VS Code task `Test: Local Patch Report` or `bash scripts/local-patch-report.sh`.
- **Verify artifacts**: Both `test-results/local-patch-report.md` and `test-results/local-patch-report.json` must exist with non-empty results.
- **Act on findings**: If patch coverage for any changed file is below **90%**, delegate to the responsible agent (`Backend_Dev` or `Frontend_Dev`) to add targeted tests covering the uncovered lines. Re-run coverage (step 2) and this report until the threshold is met.
- **Blocking gate**: 90% overall patch coverage. Do not proceed to pre-commit or security scans until resolved or explicitly waived by the user.
4. **Type Safety (Frontend)**:
- Ensure `Frontend_Dev` ran VS Code task "Lint: TypeScript Check" or `npm run type-check`
- **Why**: This check is in manual stage of pre-commit for performance. Subagents MUST run it explicitly.
5. **Pre-commit Hooks**: Ensure `QA_Security` ran `pre-commit run --all-files` (fast hooks only; coverage was verified in step 3)
5. **Pre-commit Hooks**: Ensure `QA_Security` ran `pre-commit run --all-files` (fast hooks only; coverage was verified in step 2)
6. **Security Scans**: Ensure `QA_Security` ran the following with zero Critical or High severity issues:
- **Trivy Filesystem Scan**: Fast scan of source code and dependencies

View File

@@ -2,9 +2,10 @@
name: 'Planning'
description: 'Principal Architect for technical planning and design decisions.'
argument-hint: 'The feature or system to plan (e.g., "Design the architecture for Real-Time Logs")'
tools: vscode/extensions, vscode/getProjectSetupInfo, vscode/installExtension, vscode/memory, vscode/openSimpleBrowser, vscode/runCommand, vscode/askQuestions, vscode/vscodeAPI, execute, read, agent, 'github/*', 'github/*', 'io.github.goreleaser/mcp/*', 'trivy-mcp/*', edit, search, web, 'github/*', 'playwright/*', 'pylance-mcp-server/*', todo, vscode.mermaid-chat-features/renderMermaidDiagram, github.vscode-pull-request-github/issue_fetch, github.vscode-pull-request-github/labels_fetch, github.vscode-pull-request-github/notification_fetch, github.vscode-pull-request-github/doSearch, github.vscode-pull-request-github/activePullRequest, github.vscode-pull-request-github/openPullRequest, ms-azuretools.vscode-containers/containerToolsConfig, ms-python.python/getPythonEnvironmentInfo, ms-python.python/getPythonExecutableCommand, ms-python.python/installPythonPackage, ms-python.python/configurePythonEnvironment , 'gopls/*'
tools: vscode/getProjectSetupInfo, vscode/installExtension, vscode/memory, vscode/runCommand, vscode/vscodeAPI, vscode/extensions, vscode/askQuestions, execute, read, edit, search, web, browser, github/add_comment_to_pending_review, github/add_issue_comment, github/add_reply_to_pull_request_comment, github/assign_copilot_to_issue, github/create_branch, github/create_or_update_file, github/create_pull_request, github/create_pull_request_with_copilot, github/create_repository, github/delete_file, github/fork_repository, github/get_commit, github/get_copilot_job_status, github/get_file_contents, github/get_label, github/get_latest_release, github/get_me, github/get_release_by_tag, github/get_tag, github/get_team_members, github/get_teams, github/issue_read, github/issue_write, github/list_branches, github/list_commits, github/list_issue_types, github/list_issues, github/list_pull_requests, github/list_releases, github/list_tags, github/merge_pull_request, github/pull_request_read, github/pull_request_review_write, github/push_files, github/request_copilot_review, github/search_code, github/search_issues, github/search_pull_requests, github/search_repositories, github/search_users, github/sub_issue_write, github/update_pull_request, github/update_pull_request_branch, playwright/*, github/*, io.github.goreleaser/mcp/*, mcp-refactor-typescript/*, microsoftdocs/mcp/*, vscode.mermaid-chat-features/renderMermaidDiagram, github.vscode-pull-request-github/issue_fetch, github.vscode-pull-request-github/labels_fetch, github.vscode-pull-request-github/notification_fetch, github.vscode-pull-request-github/doSearch, github.vscode-pull-request-github/activePullRequest, github.vscode-pull-request-github/pullRequestStatusChecks, github.vscode-pull-request-github/openPullRequest, ms-azuretools.vscode-containers/containerToolsConfig, ms-python.python/getPythonEnvironmentInfo, ms-python.python/getPythonExecutableCommand, ms-python.python/installPythonPackage, ms-python.python/configurePythonEnvironment, todo
model: GPT-5.3-Codex (copilot)
target: vscode
user-invocable: true
disable-model-invocation: false
@@ -37,18 +38,18 @@ You are a PRINCIPAL ARCHITECT responsible for technical planning and system desi
- Specify database schema changes
- Document component interactions and data flow
- Identify potential risks and mitigation strategies
- Determine PR sizing and whether to split the work into multiple PRs for safer and faster review
- Determine commit sizing and how to organize work into logical commits within a single PR for safer and faster review
3. **Documentation**:
- Write plan to `docs/plans/current_spec.md`
- Include acceptance criteria
- Break down into implementable tasks using examples, diagrams, and tables
- Estimate complexity for each component
- Add a **PR Slicing Strategy** section with:
- Decision: single PR or multiple PRs
- Add a **Commit Slicing Strategy** section with:
- Decision: single PR with ordered logical commits (one feature = one PR)
- Trigger reasons (scope, risk, cross-domain changes, review size)
- Ordered PR slices (`PR-1`, `PR-2`, ...), each with scope, files, dependencies, and validation gates
- Rollback and contingency notes per slice
- Ordered commits (`Commit 1`, `Commit 2`, ...), each with scope, files, dependencies, and validation gates
- Rollback and contingency notes for the PR as a whole
4. **Handoff**:
- Once plan is approved, delegate to `Supervisor` agent for review.

View File

@@ -3,9 +3,10 @@ name: 'Playwright Dev'
description: 'E2E Testing Specialist for Playwright test automation.'
argument-hint: 'The feature or flow to test (e.g., "Write E2E tests for the login flow")'
tools: vscode/extensions, vscode/getProjectSetupInfo, vscode/installExtension, vscode/memory, vscode/openIntegratedBrowser, vscode/runCommand, vscode/askQuestions, vscode/vscodeAPI, execute, read, agent, 'github/*', 'github/*', 'io.github.goreleaser/mcp/*', 'trivy-mcp/*', edit, search, web, 'github/*', 'gopls/*', 'playwright/*', 'pylance-mcp-server/*', todo, vscode.mermaid-chat-features/renderMermaidDiagram, github.vscode-pull-request-github/issue_fetch, github.vscode-pull-request-github/labels_fetch, github.vscode-pull-request-github/notification_fetch, github.vscode-pull-request-github/doSearch, github.vscode-pull-request-github/activePullRequest, github.vscode-pull-request-github/openPullRequest, ms-azuretools.vscode-containers/containerToolsConfig, ms-python.python/getPythonEnvironmentInfo, ms-python.python/getPythonExecutableCommand, ms-python.python/installPythonPackage, ms-python.python/configurePythonEnvironment
tools: vscode/getProjectSetupInfo, vscode/installExtension, vscode/memory, vscode/runCommand, vscode/vscodeAPI, vscode/extensions, vscode/askQuestions, execute, read, edit, search, web, browser, github/add_comment_to_pending_review, github/add_issue_comment, github/add_reply_to_pull_request_comment, github/assign_copilot_to_issue, github/create_branch, github/create_or_update_file, github/create_pull_request, github/create_pull_request_with_copilot, github/create_repository, github/delete_file, github/fork_repository, github/get_commit, github/get_copilot_job_status, github/get_file_contents, github/get_label, github/get_latest_release, github/get_me, github/get_release_by_tag, github/get_tag, github/get_team_members, github/get_teams, github/issue_read, github/issue_write, github/list_branches, github/list_commits, github/list_issue_types, github/list_issues, github/list_pull_requests, github/list_releases, github/list_tags, github/merge_pull_request, github/pull_request_read, github/pull_request_review_write, github/push_files, github/request_copilot_review, github/search_code, github/search_issues, github/search_pull_requests, github/search_repositories, github/search_users, github/sub_issue_write, github/update_pull_request, github/update_pull_request_branch, playwright/*, github/*, io.github.goreleaser/mcp/*, mcp-refactor-typescript/*, microsoftdocs/mcp/*, vscode.mermaid-chat-features/renderMermaidDiagram, github.vscode-pull-request-github/issue_fetch, github.vscode-pull-request-github/labels_fetch, github.vscode-pull-request-github/notification_fetch, github.vscode-pull-request-github/doSearch, github.vscode-pull-request-github/activePullRequest, github.vscode-pull-request-github/pullRequestStatusChecks, github.vscode-pull-request-github/openPullRequest, ms-azuretools.vscode-containers/containerToolsConfig, ms-python.python/getPythonEnvironmentInfo, ms-python.python/getPythonExecutableCommand, ms-python.python/installPythonPackage, ms-python.python/configurePythonEnvironment, todo
model: GPT-5.3-Codex (copilot)
target: vscode
user-invocable: true
disable-model-invocation: false

View File

@@ -2,9 +2,10 @@
name: 'QA Security'
description: 'Quality Assurance and Security Engineer for testing and vulnerability assessment.'
argument-hint: 'The component or feature to test (e.g., "Run security scan on authentication endpoints")'
tools: vscode/extensions, vscode/getProjectSetupInfo, vscode/installExtension, vscode/memory, vscode/openSimpleBrowser, vscode/runCommand, vscode/askQuestions, vscode/vscodeAPI, execute, read, agent, 'github/*', 'github/*', 'io.github.goreleaser/mcp/*', 'trivy-mcp/*', edit, search, web, 'github/*', 'playwright/*', 'pylance-mcp-server/*', todo, vscode.mermaid-chat-features/renderMermaidDiagram, github.vscode-pull-request-github/issue_fetch, github.vscode-pull-request-github/labels_fetch, github.vscode-pull-request-github/notification_fetch, github.vscode-pull-request-github/doSearch, github.vscode-pull-request-github/activePullRequest, github.vscode-pull-request-github/openPullRequest, ms-azuretools.vscode-containers/containerToolsConfig, ms-python.python/getPythonEnvironmentInfo, ms-python.python/getPythonExecutableCommand, ms-python.python/installPythonPackage, ms-python.python/configurePythonEnvironment, 'gopls/*'
tools: vscode/getProjectSetupInfo, vscode/installExtension, vscode/memory, vscode/runCommand, vscode/vscodeAPI, vscode/extensions, vscode/askQuestions, execute, read, edit, search, web, browser, github/add_comment_to_pending_review, github/add_issue_comment, github/add_reply_to_pull_request_comment, github/assign_copilot_to_issue, github/create_branch, github/create_or_update_file, github/create_pull_request, github/create_pull_request_with_copilot, github/create_repository, github/delete_file, github/fork_repository, github/get_commit, github/get_copilot_job_status, github/get_file_contents, github/get_label, github/get_latest_release, github/get_me, github/get_release_by_tag, github/get_tag, github/get_team_members, github/get_teams, github/issue_read, github/issue_write, github/list_branches, github/list_commits, github/list_issue_types, github/list_issues, github/list_pull_requests, github/list_releases, github/list_tags, github/merge_pull_request, github/pull_request_read, github/pull_request_review_write, github/push_files, github/request_copilot_review, github/search_code, github/search_issues, github/search_pull_requests, github/search_repositories, github/search_users, github/sub_issue_write, github/update_pull_request, github/update_pull_request_branch, playwright/*, github/*, io.github.goreleaser/mcp/*, mcp-refactor-typescript/*, microsoftdocs/mcp/*, vscode.mermaid-chat-features/renderMermaidDiagram, github.vscode-pull-request-github/issue_fetch, github.vscode-pull-request-github/labels_fetch, github.vscode-pull-request-github/notification_fetch, github.vscode-pull-request-github/doSearch, github.vscode-pull-request-github/activePullRequest, github.vscode-pull-request-github/pullRequestStatusChecks, github.vscode-pull-request-github/openPullRequest, ms-azuretools.vscode-containers/containerToolsConfig, ms-python.python/getPythonEnvironmentInfo, ms-python.python/getPythonExecutableCommand, ms-python.python/installPythonPackage, ms-python.python/configurePythonEnvironment, todo
model: GPT-5.3-Codex (copilot)
target: vscode
user-invocable: true
disable-model-invocation: false
@@ -13,7 +14,11 @@ You are a QA AND SECURITY ENGINEER responsible for testing and vulnerability ass
<context>
- **Governance**: When this agent file conflicts with canonical instruction
files (`.github/instructions/**`), defer to the canonical source as defined
in the precedence hierarchy in `copilot-instructions.md`.
- **MANDATORY**: Read all relevant instructions in `.github/instructions/**` for the specific task before starting.
- **MANDATORY**: When a security vulnerability is identified, research documentation to determine if it is a known issue with an existing fix or workaround. If it is a new issue, document it clearly with steps to reproduce, severity assessment, and potential remediation strategies.
- Charon is a self-hosted reverse proxy management tool
- Backend tests: `.github/skills/test-backend-unit.SKILL.md`
- Frontend tests: `.github/skills/test-frontend-react.SKILL.md`
@@ -40,6 +45,19 @@ You are a QA AND SECURITY ENGINEER responsible for testing and vulnerability ass
- Review test failure outputs with `test_failure` tool
4. **Security Scanning**:
- - Review Security: Read `security.md.instrutctions.md` and `SECURITY.md` to understand the security requirements and best practices for Charon. Ensure that any open concerns or issues are addressed in the QA Audit and `SECURITY.md` is updated accordingly.
- **Conditional GORM Scan**: When backend model/database-related changes are
in scope (`backend/internal/models/**`, GORM services, migrations), run
GORM scanner in check mode and report pass/fail as DoD gate:
- Run: VS Code task `Lint: GORM Security Scan` OR
`./scripts/scan-gorm-security.sh --check`
- Block approval on unresolved CRITICAL/HIGH findings
- **Gotify Token Review**: Verify no Gotify tokens appear in:
- Logs, test artifacts, screenshots
- API examples, report output
- Tokenized URL query strings (e.g., `?token=...`)
- Verify URL query parameters are redacted in
diagnostics/examples/log artifacts
- Run Trivy scans on filesystem and container images
- Analyze vulnerabilities with `mcp_trivy_mcp_findings_list`
- Prioritize by severity (CRITICAL > HIGH > MEDIUM > LOW)

View File

@@ -2,9 +2,9 @@
name: 'Supervisor'
description: 'Code Review Lead for quality assurance and PR review.'
argument-hint: 'The PR or code change to review (e.g., "Review PR #123 for security issues")'
tools: vscode/extensions, vscode/getProjectSetupInfo, vscode/installExtension, vscode/memory, vscode/openSimpleBrowser, vscode/runCommand, vscode/askQuestions, vscode/vscodeAPI, execute, read, agent, 'github/*', 'github/*', 'io.github.goreleaser/mcp/*', 'trivy-mcp/*', edit, search, web, 'github/*', 'playwright/*', 'pylance-mcp-server/*', todo, vscode.mermaid-chat-features/renderMermaidDiagram, github.vscode-pull-request-github/issue_fetch, github.vscode-pull-request-github/labels_fetch, github.vscode-pull-request-github/notification_fetch, github.vscode-pull-request-github/doSearch, github.vscode-pull-request-github/activePullRequest, github.vscode-pull-request-github/openPullRequest, ms-azuretools.vscode-containers/containerToolsConfig, ms-python.python/getPythonEnvironmentInfo, ms-python.python/getPythonExecutableCommand, ms-python.python/installPythonPackage, ms-python.python/configurePythonEnvironment, 'gopls/*'
tools: vscode/getProjectSetupInfo, vscode/installExtension, vscode/memory, vscode/runCommand, vscode/vscodeAPI, vscode/extensions, vscode/askQuestions, execute, read, edit, search, web, browser, github/add_comment_to_pending_review, github/add_issue_comment, github/add_reply_to_pull_request_comment, github/assign_copilot_to_issue, github/create_branch, github/create_or_update_file, github/create_pull_request, github/create_pull_request_with_copilot, github/create_repository, github/delete_file, github/fork_repository, github/get_commit, github/get_copilot_job_status, github/get_file_contents, github/get_label, github/get_latest_release, github/get_me, github/get_release_by_tag, github/get_tag, github/get_team_members, github/get_teams, github/issue_read, github/issue_write, github/list_branches, github/list_commits, github/list_issue_types, github/list_issues, github/list_pull_requests, github/list_releases, github/list_tags, github/merge_pull_request, github/pull_request_read, github/pull_request_review_write, github/push_files, github/request_copilot_review, github/search_code, github/search_issues, github/search_pull_requests, github/search_repositories, github/search_users, github/sub_issue_write, github/update_pull_request, github/update_pull_request_branch, playwright/*, github/*, io.github.goreleaser/mcp/*, mcp-refactor-typescript/*, microsoftdocs/mcp/*, vscode.mermaid-chat-features/renderMermaidDiagram, github.vscode-pull-request-github/issue_fetch, github.vscode-pull-request-github/labels_fetch, github.vscode-pull-request-github/notification_fetch, github.vscode-pull-request-github/doSearch, github.vscode-pull-request-github/activePullRequest, github.vscode-pull-request-github/pullRequestStatusChecks, github.vscode-pull-request-github/openPullRequest, ms-azuretools.vscode-containers/containerToolsConfig, ms-python.python/getPythonEnvironmentInfo, ms-python.python/getPythonExecutableCommand, ms-python.python/installPythonPackage, ms-python.python/configurePythonEnvironment, todo
model: GPT-5.3-Codex (copilot)
target: vscode
user-invocable: true
disable-model-invocation: false
@@ -15,8 +15,10 @@ You are a CODE REVIEW LEAD responsible for quality assurance and maintaining cod
- **MANDATORY**: Read all relevant instructions in `.github/instructions/` for the specific task before starting.
- Charon is a self-hosted reverse proxy management tool
- The codebase includes Go for backend and TypeScript for frontend
- Code style: Go follows `gofmt`, TypeScript follows ESLint config
- Review guidelines: `.github/instructions/code-review-generic.instructions.md`
- Think "mature Saas product codebase with security-sensitive features and a high standard for code quality" over "open source project with varying contribution quality"
- Security guidelines: `.github/instructions/security-and-owasp.instructions.md`
</context>

View File

@@ -1,7 +0,0 @@
{
"schemaVersion": 1,
"label": "GHCR pulls",
"message": "0",
"color": "blue",
"cacheSeconds": 3600
}

View File

@@ -126,11 +126,11 @@ graph TB
| **HTTP Framework** | Gin | Latest | Routing, middleware, HTTP handling |
| **Database** | SQLite | 3.x | Embedded database |
| **ORM** | GORM | Latest | Database abstraction layer |
| **Reverse Proxy** | Caddy Server | 2.11.0-beta.2 | Embedded HTTP/HTTPS proxy |
| **Reverse Proxy** | Caddy Server | 2.11.2 | Embedded HTTP/HTTPS proxy |
| **WebSocket** | gorilla/websocket | Latest | Real-time log streaming |
| **Crypto** | golang.org/x/crypto | Latest | Password hashing, encryption |
| **Metrics** | Prometheus Client | Latest | Application metrics |
| **Notifications** | Shoutrrr | Latest | Multi-platform alerts |
| **Notifications** | Notify | Latest | Multi-platform alerts |
| **Docker Client** | Docker SDK | Latest | Container discovery |
| **Logging** | Logrus + Lumberjack | Latest | Structured logging with rotation |
@@ -1263,8 +1263,8 @@ docker exec charon /app/scripts/restore-backup.sh \
- Future: Dynamic plugin loading for custom providers
2. **Notification Channels:**
- Shoutrrr provides 40+ channels (Discord, Slack, Email, etc.)
- Custom channels via Shoutrrr service URLs
- Notify provides multi-platform channels (Discord, Slack, Gotify, etc.)
- Provider-based configuration with per-channel feature flags
3. **Authentication Providers:**
- Current: Local database authentication

View File

@@ -17,6 +17,23 @@ Every session should improve the codebase, not just add to it. Actively refactor
- **READABLE**: Maintain comments and clear naming for complex logic. Favor clarity over cleverness.
- **CONVENTIONAL COMMITS**: Write commit messages using `feat:`, `fix:`, `chore:`, `refactor:`, or `docs:` prefixes.
## Governance & Precedence
When policy statements conflict across documentation sources, resolve using this precedence hierarchy:
1. **Highest Precedence**: `.github/instructions/**` files (canonical source of truth)
2. **Agent Overrides**: `.github/agents/**` files (agent-specific customizations)
3. **Operator Documentation**: `SECURITY.md`, `docs/security.md`,
`docs/features/notifications.md` (user-facing guidance)
**Reconciliation Rule**: When conflicts arise, the stricter security requirement
wins. Update downstream documentation to match canonical text in
`.github/instructions/**`.
**Example**: If `.github/instructions/security.instructions.md` mandates token
redaction but operator docs suggest logging is acceptable, token redaction
requirement takes precedence and operator docs must be updated.
## 🚨 CRITICAL ARCHITECTURE RULES 🚨
- **Single Frontend Source**: All frontend code MUST reside in `frontend/`. NEVER create `backend/frontend/` or any other nested frontend directory.
@@ -50,7 +67,7 @@ Before proposing ANY code change or fix, you must build a mental map of the feat
- **Run**: `cd backend && go run ./cmd/api`.
- **Test**: `go test ./...`.
- **Static Analysis (BLOCKING)**: Fast linters run automatically on every commit via pre-commit hooks.
- **Static Analysis (BLOCKING)**: Fast linters run automatically on every commit via lefthook pre-commit-phase hooks.
- **Staticcheck errors MUST be fixed** - commits are BLOCKED until resolved
- Manual run: `make lint-fast` or VS Code task "Lint: Staticcheck (Fast)"
- Staticcheck-only: `make lint-staticcheck-only`
@@ -62,7 +79,7 @@ Before proposing ANY code change or fix, you must build a mental map of the feat
- **Security**: Sanitize all file paths using `filepath.Clean`. Use `fmt.Errorf("context: %w", err)` for error wrapping.
- **Graceful Shutdown**: Long-running work must respect `server.Run(ctx)`.
### Troubleshooting Pre-Commit Staticcheck Failures
### Troubleshooting Lefthook Staticcheck Failures
**Common Issues:**
@@ -150,6 +167,21 @@ Before marking an implementation task as complete, perform the following in orde
- **Base URL**: Uses `PLAYWRIGHT_BASE_URL` or default from `playwright.config.js`
- All E2E tests must pass before proceeding to unit tests
1.5. **GORM Security Scan** (CONDITIONAL, BLOCKING):
- **Trigger Condition**: Execute this gate when changes include backend models or database interaction logic:
- `backend/internal/models/**`
- GORM query/service layers
- Database migrations or seeding logic
- **Exclusions**: Skip this gate for docs-only (`**/*.md`) or frontend-only (`frontend/**`) changes
- **Run One Of**:
- VS Code task: `Lint: GORM Security Scan`
- Lefthook: `lefthook run pre-commit` (includes gorm-security-scan)
- Direct: `./scripts/scan-gorm-security.sh --check`
- **Gate Enforcement**: DoD is process-blocking until scanner reports zero
CRITICAL/HIGH findings, even while automation remains in manual stage
- **Check Mode Required**: Gate decisions must use check mode semantics
(`--check` flag or equivalent task wiring) for pass/fail determination
2. **Local Patch Coverage Preflight** (MANDATORY - Run Before Unit/Coverage Tests):
- **Run**: VS Code task `Test: Local Patch Report` or `bash scripts/local-patch-report.sh` from repo root.
- **Purpose**: Surface exact changed files and uncovered changed lines before adding/refining unit tests.
@@ -157,15 +189,15 @@ Before marking an implementation task as complete, perform the following in orde
- **Expected Behavior**: Report may warn (non-blocking rollout), but artifact generation is mandatory.
3. **Security Scans** (MANDATORY - Zero Tolerance):
- **CodeQL Go Scan**: Run VS Code task "Security: CodeQL Go Scan (CI-Aligned)" OR `pre-commit run codeql-go-scan --all-files`
- **CodeQL Go Scan**: Run VS Code task "Security: CodeQL Go Scan (CI-Aligned)" OR `lefthook run pre-commit`
- Must use `security-and-quality` suite (CI-aligned)
- **Zero high/critical (error-level) findings allowed**
- Medium/low findings should be documented and triaged
- **CodeQL JS Scan**: Run VS Code task "Security: CodeQL JS Scan (CI-Aligned)" OR `pre-commit run codeql-js-scan --all-files`
- **CodeQL JS Scan**: Run VS Code task "Security: CodeQL JS Scan (CI-Aligned)" OR `lefthook run pre-commit`
- Must use `security-and-quality` suite (CI-aligned)
- **Zero high/critical (error-level) findings allowed**
- Medium/low findings should be documented and triaged
- **Validate Findings**: Run `pre-commit run codeql-check-findings --all-files` to check for HIGH/CRITICAL issues
- **Validate Findings**: Run `lefthook run pre-commit` to check for HIGH/CRITICAL issues
- **Trivy Container Scan**: Run VS Code task "Security: Trivy Scan" for container/dependency vulnerabilities
- **Results Viewing**:
- Primary: VS Code SARIF Viewer extension (`MS-SarifVSCode.sarif-viewer`)
@@ -178,7 +210,7 @@ Before marking an implementation task as complete, perform the following in orde
- Database creation: `--threads=0 --overwrite`
- Analysis: `--sarif-add-baseline-file-info`
4. **Pre-Commit Triage**: Run `pre-commit run --all-files`.
4. **Lefthook Triage**: Run `lefthook run pre-commit`.
- If errors occur, **fix them immediately**.
- If logic errors occur, analyze and propose a fix.
- Do not output code that violates pre-commit standards.

View File

@@ -353,7 +353,7 @@ Follow idiomatic Go practices and community standards when writing Go code. Thes
### Development Practices
- Run tests before committing
- Use pre-commit hooks for formatting and linting
- Use lefthook pre-commit-phase hooks for formatting and linting
- Keep commits focused and atomic
- Write meaningful commit messages
- Review diffs before committing

View File

@@ -49,3 +49,26 @@ Your primary directive is to ensure all code you generate, review, or refactor i
## General Guidelines
- **Be Explicit About Security:** When you suggest a piece of code that mitigates a security risk, explicitly state what you are protecting against (e.g., "Using a parameterized query here to prevent SQL injection.").
- **Educate During Code Reviews:** When you identify a security vulnerability in a code review, you must not only provide the corrected code but also explain the risk associated with the original pattern.
### Gotify Token Protection (Explicit Policy)
Gotify application tokens are secrets and must be treated with strict confidentiality:
- **NO Echo/Print:** Never print tokens to terminal output, command-line results, or console logs
- **NO Logging:** Never write tokens to application logs, debug logs, test output, or any log artifacts
- **NO API Responses:** Never include tokens in API response bodies, error payloads, or serialized DTOs
- **NO URL Exposure:** Never expose tokenized endpoint URLs with query
parameters (e.g., `https://gotify.example.com/message?token=...`) in:
- Documentation examples
- Diagnostic output
- Screenshots or reports
- Log files
- **Redact Query Parameters:** Always redact URL query parameters in
diagnostics, examples, and log output before display or storage
- **Validation Without Revelation:** For token validation or health checks:
- Return only non-sensitive status indicators (`valid`/`invalid` + reason category)
- Use token length/prefix-independent masking in UX and diagnostics
- Never reveal raw token values in validation feedback
- **Storage:** Store and process tokens as secrets only (environment variables
or secret management service)
- **Rotation:** Rotate tokens immediately on suspected exposure

View File

@@ -0,0 +1,204 @@
---
applyTo: SECURITY.md
---
# Instructions: Maintaining `SECURITY.md`
`SECURITY.md` is the project's living security record. It serves two audiences simultaneously: users who need to know what risks exist right now, and the broader community who need confidence that vulnerabilities are being tracked and remediated with discipline. Treat it like a changelog, but for security events — every known issue gets an entry, every resolved issue keeps its entry.
---
## File Structure
`SECURITY.md` must always contain the following top-level sections, in this order:
1. A brief project security policy preamble (responsible disclosure contact, response SLA)
2. **`## Known Vulnerabilities`** — active, unpatched issues
3. **`## Patched Vulnerabilities`** — resolved issues, retained permanently for audit trail
No other top-level sections are required. Do not collapse or remove sections even when they are empty — use the explicit empty-state placeholder defined below.
---
## Section 1: Known Vulnerabilities
This section lists every vulnerability that is currently unpatched or only partially mitigated. Entries must be sorted with the highest severity first, then by discovery date descending within the same severity tier.
### Entry Format
Each entry is an H3 heading followed by a structured block:
```markdown
### [SEVERITY] CVE-XXXX-XXXXX · Short Title
| Field | Value |
|--------------|-------|
| **ID** | CVE-XXXX-XXXXX (or `CHARON-YYYY-NNN` if no CVE assigned yet) |
| **Severity** | Critical / High / Medium / Low · CVSS v3.1 score if known (e.g. `8.1 · High`) |
| **Status** | Investigating / Fix In Progress / Awaiting Upstream / Mitigated (partial) |
**What**
One to three sentences describing the vulnerability class and its impact.
Be specific: name the weakness type (e.g. SQL injection, path traversal, SSRF).
**Who**
- Discovered by: [Reporter name or handle, or "Internal audit", or "Automated scan (tool name)"]
- Reported: YYYY-MM-DD
- Affects: [User roles, API consumers, unauthenticated users, etc.]
**Where**
- Component: [Module or service name]
- File(s): `path/to/affected/file.go`, `path/to/other/file.ts`
- Versions affected: `>= X.Y.Z` (or "all versions" / "prior to X.Y.Z")
**When**
- Discovered: YYYY-MM-DD
- Disclosed (if public): YYYY-MM-DD (or "Not yet publicly disclosed")
- Target fix: YYYY-MM-DD (or sprint/milestone reference)
**How**
A concise technical description of the attack vector, prerequisites, and exploitation
method. Omit proof-of-concept code. Reference CVE advisories or upstream issue
trackers where appropriate.
**Planned Remediation**
Describe the fix strategy: library upgrade, logic refactor, config change, etc.
If a workaround is available in the meantime, document it here.
Link to the tracking issue: [#NNN](https://github.com/owner/repo/issues/NNN)
```
### Empty State
When there are no known vulnerabilities:
```markdown
## Known Vulnerabilities
No known unpatched vulnerabilities at this time.
Last reviewed: YYYY-MM-DD
```
---
## Section 2: Patched Vulnerabilities
This section is a permanent, append-only ledger. Entries are never deleted. Sort newest-patched first. This section builds community trust by demonstrating that issues are resolved promptly and transparently.
### Entry Format
```markdown
### ✅ [SEVERITY] CVE-XXXX-XXXXX · Short Title
| Field | Value |
|--------------|-------|
| **ID** | CVE-XXXX-XXXXX (or internal ID) |
| **Severity** | Critical / High / Medium / Low · CVSS v3.1 score |
| **Patched** | YYYY-MM-DD in `vX.Y.Z` |
**What**
Same description carried over from the Known Vulnerabilities entry.
**Who**
- Discovered by: [Reporter or method]
- Reported: YYYY-MM-DD
**Where**
- Component: [Module or service name]
- File(s): `path/to/affected/file.go`
- Versions affected: `< X.Y.Z`
**When**
- Discovered: YYYY-MM-DD
- Patched: YYYY-MM-DD
- Time to patch: N days
**How**
Same technical description as the original entry.
**Resolution**
Describe exactly what was changed to fix the issue.
- Commit: [`abc1234`](https://github.com/owner/repo/commit/abc1234)
- PR: [#NNN](https://github.com/owner/repo/pull/NNN)
- Release: [`vX.Y.Z`](https://github.com/owner/repo/releases/tag/vX.Y.Z)
**Credit**
[Optional] Thank the reporter if they consented to attribution.
```
### Empty State
```markdown
## Patched Vulnerabilities
No patched vulnerabilities on record yet.
```
---
## Lifecycle: Moving an Entry from Known → Patched
When a fix ships:
1. Remove the entry from `## Known Vulnerabilities` entirely.
2. Add a new entry to the **top** of `## Patched Vulnerabilities` using the patched format above.
3. Carry forward all original fields verbatim — do not rewrite the history of the issue.
4. Add the `**Resolution**` and `**Credit**` blocks with patch details.
5. Update the `Last reviewed` date on the Known Vulnerabilities section if it is now empty.
Do not edit or backfill existing Patched entries once they are committed.
---
## Severity Classification
Use the following definitions consistently:
| Severity | CVSS Range | Meaning |
|----------|------------|---------|
| **Critical** | 9.010.0 | Remote code execution, auth bypass, full data exposure |
| **High** | 7.08.9 | Significant data exposure, privilege escalation, DoS |
| **Medium** | 4.06.9 | Limited data exposure, requires user interaction or auth |
| **Low** | 0.13.9 | Minimal impact, difficult to exploit, defense-in-depth |
When a CVE CVSS score is not yet available, assign a preliminary severity based on these definitions and note it as `(preliminary)` until confirmed.
---
## Internal IDs
If a vulnerability has no CVE assigned, use the format `CHARON-YYYY-NNN` where `YYYY` is the year and `NNN` is a zero-padded sequence number starting at `001` for each year. Example: `CHARON-2025-003`. Assign a CVE ID in the entry retroactively if one is issued later, and add the internal ID as an alias in parentheses.
---
## Responsible Disclosure Preamble
The preamble at the top of `SECURITY.md` (before the vulnerability sections) must include:
- The preferred contact method for reporting vulnerabilities (e.g. a GitHub private advisory link, a security email address, or both)
- An acknowledgment-first response commitment: confirm receipt within 48 hours, even if the full investigation takes longer
- A statement that reporters will not be penalized or publicly named without consent
- A link to the full disclosure policy if one exists
Example:
```markdown
## Reporting a Vulnerability
To report a security issue, please use
[GitHub Private Security Advisories](https://github.com/owner/repo/security/advisories/new)
or email `security@example.com`.
We will acknowledge your report within **48 hours** and provide a remediation
timeline within **7 days**. Reporters are credited with their consent.
We do not pursue legal action against good-faith security researchers.
```
---
## Maintenance Rules
- **Review cadence**: Update the `Last reviewed` date in the Known Vulnerabilities section at least once per release cycle, even if no entries changed.
- **No silent patches**: Every security fix — no matter how minor — must produce an entry in `## Patched Vulnerabilities` before or alongside the release.
- **No redaction**: Do not redact or soften historical entries. Accuracy builds trust; minimizing past issues destroys it.
- **Dependency vulnerabilities**: Transitive dependency CVEs that affect Charon's exposed attack surface must be tracked here the same as first-party vulnerabilities. Pure dev-dependency CVEs with no runtime impact may be omitted at maintainer discretion, but must still be noted in the relevant dependency update PR.
- **Partial mitigations**: If a workaround is deployed but the root cause is not fixed, the entry stays in `## Known Vulnerabilities` with `Status: Mitigated (partial)` and the workaround documented in `**Planned Remediation**`.

View File

@@ -9,7 +9,7 @@ description: 'Repository structure guidelines to maintain organized file placeme
The repository root should contain ONLY:
- Essential config files (`.gitignore`, `.pre-commit-config.yaml`, `Makefile`, etc.)
- Essential config files (`.gitignore`, `Makefile`, etc.)
- Standard project files (`README.md`, `CONTRIBUTING.md`, `LICENSE`, `CHANGELOG.md`)
- Go workspace files (`go.work`, `go.work.sum`)
- VS Code workspace (`Chiron.code-workspace`)

View File

@@ -23,21 +23,21 @@ runSubagent({
- Validate: `plan_file` exists and contains a `Handoff Contract` JSON.
- Kickoff: call `Planning` to create the plan if not present.
- Decide: check if work should be split into multiple PRs (size, risk, cross-domain impact).
- Decide: check how to organize work into logical commits within a single PR (size, risk, cross-domain impact).
- Run: execute `Backend Dev` then `Frontend Dev` sequentially.
- Parallel: run `QA and Security`, `DevOps` and `Doc Writer` in parallel for CI / QA checks and documentation.
- Return: a JSON summary with `subagent_results`, `overall_status`, and aggregated artifacts.
2.1) Multi-PR Slicing Protocol
2.1) Multi-Commit Slicing Protocol
- If a task is large or high-risk, split into PR slices and execute in order.
- Each slice must have:
- All work for a single feature ships as one PR with ordered logical commits.
- Each commit must have:
- Scope boundary (what is included/excluded)
- Dependency on previous slices
- Validation gates (tests/scans required for that slice)
- Explicit rollback notes
- Do not start the next slice until the current slice is complete and verified.
- Keep each slice independently reviewable and deployable.
- Dependency on previous commits
- Validation gates (tests/scans required for that commit)
- Explicit rollback notes for the PR as a whole
- Do not start the next commit until the current commit is complete and verified.
- Keep each commit independently reviewable within the PR.
3) Return Contract that all subagents must return
@@ -55,7 +55,7 @@ runSubagent({
- On a subagent failure, the Management agent must capture `tests.output` and decide to retry (1 retry maximum), or request a revert/rollback.
- Clearly mark the `status` as `failed`, and include `errors` and `failing_tests` in the `summary`.
- For multi-PR execution, mark failed slice as blocked and stop downstream slices until resolved.
- For multi-commit execution, mark failed commit as blocked and stop downstream commits until resolved.
5) Example: Run a full Feature Implementation

View File

@@ -4,13 +4,27 @@ description: 'Strict protocols for test execution, debugging, and coverage valid
---
# Testing Protocols
**Governance Note**: This file is subject to the precedence hierarchy defined in
`.github/instructions/copilot-instructions.md`. When conflicts arise, canonical
instruction files take precedence over agent files and operator documentation.
## 0. E2E Verification First (Playwright)
**MANDATORY**: Before running unit tests, verify the application UI/UX functions correctly end-to-end.
## 0.5 Local Patch Coverage Preflight (Before Unit Tests)
## 0.5 Local Patch Coverage Report (After Coverage Tests)
**MANDATORY**: After E2E and before backend/frontend unit coverage runs, generate a local patch report so uncovered changed lines are visible early.
**MANDATORY**: After running backend and frontend coverage tests (which generate
`backend/coverage.txt` and `frontend/coverage/lcov.info`), run the local patch
report to identify uncovered lines in changed files.
**Purpose**: Overall coverage can be healthy while the specific lines you changed
are untested. This step catches that gap. If uncovered lines are found in
feature code, add targeted tests before completing the task.
**Prerequisites**: Coverage artifacts must exist before running the report:
- `backend/coverage.txt` — generated by `scripts/go-test-coverage.sh`
- `frontend/coverage/lcov.info` — generated by `scripts/frontend-test-coverage.sh`
Run one of the following from `/projects/Charon`:
@@ -22,11 +36,14 @@ Test: Local Patch Report
bash scripts/local-patch-report.sh
```
Required artifacts:
Required output artifacts:
- `test-results/local-patch-report.md`
- `test-results/local-patch-report.json`
This preflight is advisory for thresholds during rollout, but artifact generation is required in DoD.
**Action on results**: If patch coverage for any changed file is below 90%, add
tests targeting the uncovered changed lines. Re-run coverage and this report to
verify improvement. Artifact generation is required for DoD regardless of
threshold results.
### PREREQUISITE: Start E2E Environment
@@ -170,16 +187,39 @@ Before pushing code, verify E2E coverage:
* **Threshold Compliance:** You must compare the final coverage percentage against the project's threshold (Default: 85% unless specified otherwise). If coverage drops, you must identify the "uncovered lines" and add targeted tests.
* **Patch Coverage (Suggestion):** Codecov reports patch coverage as an indicator. While developers should aim for 100% coverage of modified lines, patch coverage is **not a hard requirement** and will not block PR approval. If patch coverage is low, consider adding targeted tests to improve the metric.
* **Review Patch Coverage:** When reviewing patch coverage reports, assess whether missing lines represent genuine gaps or are acceptable (e.g., error handling branches, deprecated code paths). Use the report to inform testing decisions, not as an absolute gate.
## 4. GORM Security Validation (Manual Stage)
**Requirement:** All backend changes involving GORM models or database interactions must pass the GORM Security Scanner.
**Requirement:** For any change that touches backend models or
database-related logic, the GORM Security Scanner is a mandatory local DoD gate
and must pass with zero CRITICAL/HIGH findings.
### When to Run
**Policy vs. Automation Reconciliation:** "Manual stage" describes execution
mechanism only (not automated pre-commit hook); policy enforcement remains
process-blocking for DoD. Gate decisions must use check semantics
(`./scripts/scan-gorm-security.sh --check` or equivalent task wiring).
* **Before Committing:** When modifying GORM models (files in `backend/internal/models/`)
* **Before Opening PR:** Verify no security issues introduced
* **After Code Review:** If model-related changes were requested
* **Definition of Done:** Scanner must pass with zero CRITICAL/HIGH issues
### When to Run (Conditional Trigger Matrix)
**Mandatory Trigger Paths (Include):**
- `backend/internal/models/**` — GORM model definitions
- Backend services/repositories with GORM query logic
- Database migrations or seeding logic affecting model persistence behavior
**Explicit Exclusions:**
- Docs-only changes (`**/*.md`, governance documentation)
- Frontend-only changes (`frontend/**`)
**Gate Decision Rule:** IF any Include path matches, THEN scanner execution in
check mode is mandatory DoD gate. IF only Exclude paths match, THEN GORM gate
is not required for that change set.
### Definition of Done
- **Before Committing:** When modifying trigger paths listed above
- **Before Opening PR:** Verify no security issues introduced
- **After Code Review:** If model-related changes were requested
- **Blocking Gate:** Scanner must pass with zero CRITICAL/HIGH issues before
task completion
### Running the Scanner

170
.github/renovate.json vendored
View File

@@ -6,11 +6,11 @@
":separateMultipleMajorReleases",
"helpers:pinGitHubActionDigests"
],
"baseBranches": [
"baseBranchPatterns": [
"feature/beta-release",
"development"
],
"postUpdateOptions": ["npmDedupe"],
"timezone": "America/New_York",
"dependencyDashboard": true,
"dependencyDashboardApproval": true,
@@ -27,7 +27,10 @@
"rebaseWhen": "auto",
"vulnerabilityAlerts": {
"enabled": true
"enabled": true,
"dependencyDashboardApproval": false,
"automerge": false,
"labels": ["security", "vulnerability"]
},
"rangeStrategy": "bump",
@@ -36,6 +39,19 @@
"platformAutomerge": true,
"customManagers": [
{
"customType": "regex",
"description": "Track caddy-security plugin version in Dockerfile",
"managerFilePatterns": [
"/^Dockerfile$/"
],
"matchStrings": [
"ARG CADDY_SECURITY_VERSION=(?<currentValue>[^\\s]+)"
],
"depNameTemplate": "github.com/greenpau/caddy-security",
"datasourceTemplate": "go",
"versioningTemplate": "semver"
},
{
"customType": "regex",
"description": "Track Go dependencies patched in Dockerfile for Caddy CVE fixes",
@@ -53,12 +69,45 @@
"description": "Track Alpine base image digest in Dockerfile for security updates",
"managerFilePatterns": ["/^Dockerfile$/"],
"matchStrings": [
"#\\s*renovate:\\s*datasource=docker\\s+depName=alpine.*\\nARG CADDY_IMAGE=alpine:(?<currentValue>[^\\s@]+@sha256:[a-f0-9]+)"
"#\\s*renovate:\\s*datasource=docker\\s+depName=alpine.*\\nARG ALPINE_IMAGE=alpine:(?<currentValue>[^@\\s]+)@(?<currentDigest>sha256:[a-f0-9]+)"
],
"depNameTemplate": "alpine",
"datasourceTemplate": "docker",
"versioningTemplate": "docker"
},
{
"customType": "regex",
"description": "Track Go toolchain version ARG in Dockerfile",
"managerFilePatterns": ["/^Dockerfile$/"],
"matchStrings": [
"#\\s*renovate:\\s*datasource=docker\\s+depName=golang.*\\nARG GO_VERSION=(?<currentValue>[^\\s]+)"
],
"depNameTemplate": "golang",
"datasourceTemplate": "docker",
"versioningTemplate": "docker"
},
{
"customType": "regex",
"description": "Track expr-lang version ARG in Dockerfile",
"managerFilePatterns": ["/^Dockerfile$/"],
"matchStrings": [
"#\\s*renovate:\\s*datasource=go\\s+depName=github\\.com/expr-lang/expr.*\\nARG EXPR_LANG_VERSION=(?<currentValue>[^\\s]+)"
],
"depNameTemplate": "github.com/expr-lang/expr",
"datasourceTemplate": "go",
"versioningTemplate": "semver"
},
{
"customType": "regex",
"description": "Track golang.org/x/net version ARG in Dockerfile",
"managerFilePatterns": ["/^Dockerfile$/"],
"matchStrings": [
"#\\s*renovate:\\s*datasource=go\\s+depName=golang\\.org/x/net.*\\nARG XNET_VERSION=(?<currentValue>[^\\s]+)"
],
"depNameTemplate": "golang.org/x/net",
"datasourceTemplate": "go",
"versioningTemplate": "semver"
},
{
"customType": "regex",
"description": "Track Delve version in Dockerfile",
@@ -81,6 +130,32 @@
"datasourceTemplate": "go",
"versioningTemplate": "semver"
},
{
"customType": "regex",
"description": "Track gotestsum version in codecov workflow",
"managerFilePatterns": [
"/^\\.github/workflows/codecov-upload\\.yml$/"
],
"matchStrings": [
"gotestsum@v(?<currentValue>[^\\s]+)"
],
"depNameTemplate": "gotest.tools/gotestsum",
"datasourceTemplate": "go",
"versioningTemplate": "semver"
},
{
"customType": "regex",
"description": "Track gotestsum version in quality checks workflow",
"managerFilePatterns": [
"/^\\.github/workflows/quality-checks\\.yml$/"
],
"matchStrings": [
"gotestsum@v(?<currentValue>[^\\s]+)"
],
"depNameTemplate": "gotest.tools/gotestsum",
"datasourceTemplate": "go",
"versioningTemplate": "semver"
},
{
"customType": "regex",
"description": "Track govulncheck version in scripts",
@@ -117,27 +192,78 @@
{
"customType": "regex",
"description": "Track GO_VERSION in Actions workflows",
"fileMatch": ["^\\.github/workflows/.*\\.yml$"],
"managerFilePatterns": ["/^\\.github/workflows/.*\\.yml$/"],
"matchStrings": [
"GO_VERSION: ['\"]?(?<currentValue>[\\d\\.]+)['\"]?"
],
"depNameTemplate": "golang/go",
"datasourceTemplate": "golang-version",
"versioningTemplate": "semver"
},
{
"customType": "regex",
"description": "Track Syft version in workflows and scripts",
"managerFilePatterns": [
"/^\\.github/workflows/nightly-build\\.yml$/",
"/^\\.github/skills/security-scan-docker-image-scripts/run\\.sh$/"
],
"matchStrings": [
"SYFT_VERSION=\\\"v(?<currentValue>[^\\\"\\s]+)\\\"",
"set_default_env \\\"SYFT_VERSION\\\" \\\"v(?<currentValue>[^\\\"]+)\\\""
],
"depNameTemplate": "anchore/syft",
"datasourceTemplate": "github-releases",
"versioningTemplate": "semver",
"extractVersionTemplate": "^v(?<version>.*)$"
},
{
"customType": "regex",
"description": "Track Grype version in workflows and scripts",
"managerFilePatterns": [
"/^\\.github/workflows/supply-chain-pr\\.yml$/",
"/^\\.github/skills/security-scan-docker-image-scripts/run\\.sh$/"
],
"matchStrings": [
"anchore/grype/main/install\\.sh \\| sh -s -- -b /usr/local/bin v(?<currentValue>[0-9]+\\.[0-9]+\\.[0-9]+)",
"set_default_env \\\"GRYPE_VERSION\\\" \\\"v(?<currentValue>[^\\\"]+)\\\""
],
"depNameTemplate": "anchore/grype",
"datasourceTemplate": "github-releases",
"versioningTemplate": "semver",
"extractVersionTemplate": "^v(?<version>.*)$"
},
{
"customType": "regex",
"description": "Track go-version in skill example workflows",
"managerFilePatterns": ["/^\\.github/skills/examples/.*\\.yml$/"],
"matchStrings": [
"go-version: [\"']?(?<currentValue>[\\d\\.]+)[\"']?"
],
"depNameTemplate": "golang/go",
"datasourceTemplate": "golang-version",
"versioningTemplate": "semver"
}
],
"github-actions": {
"managerFilePatterns": [
"/^\\.github/skills/examples/.*\\.ya?ml$/"
]
},
"packageRules": [
{
"description": "THE MEGAZORD: Group ALL non-major updates (NPM, Docker, Go, Actions) into one PR",
"matchPackagePatterns": ["*"],
"matchUpdateTypes": [
"minor",
"patch",
"pin",
"digest"
],
"groupName": "non-major-updates"
"groupName": "non-major-updates",
"matchPackageNames": [
"*"
]
},
{
"description": "Feature branches: Auto-merge non-major updates after proven stable",
@@ -169,11 +295,41 @@
"matchPackageNames": ["caddy"],
"allowedVersions": "<3.0.0"
},
{
"description": "Go: keep pgx within v4 (CrowdSec requires pgx/v4 module path)",
"matchDatasources": ["go"],
"matchPackageNames": ["github.com/jackc/pgx/v4"],
"allowedVersions": "<5.0.0"
},
{
"description": "Go: keep go-jose/v3 within v3 (v4 is a different Go module path)",
"matchDatasources": ["go"],
"matchPackageNames": ["github.com/go-jose/go-jose/v3"],
"allowedVersions": "<4.0.0"
},
{
"description": "Go: keep go-jose/v4 within v4 (v5 would be a different Go module path)",
"matchDatasources": ["go"],
"matchPackageNames": ["github.com/go-jose/go-jose/v4"],
"allowedVersions": "<5.0.0"
},
{
"description": "Safety: Keep MAJOR updates separate and require manual review",
"matchUpdateTypes": ["major"],
"automerge": false,
"labels": ["manual-review"]
},
{
"description": "Fix Renovate lookup for geoip2-golang v2 module path",
"matchDatasources": ["go"],
"matchPackageNames": ["github.com/oschwald/geoip2-golang/v2"],
"sourceUrl": "https://github.com/oschwald/geoip2-golang"
},
{
"description": "Fix Renovate lookup for google/uuid",
"matchDatasources": ["go"],
"matchPackageNames": ["github.com/google/uuid"],
"sourceUrl": "https://github.com/google/uuid"
}
]
}

55
.github/security-severity-policy.yml vendored Normal file
View File

@@ -0,0 +1,55 @@
version: 1
effective_date: 2026-02-25
scope:
- local pre-commit manual security hooks
- github actions security workflows
defaults:
blocking:
- critical
- high
medium:
mode: risk-based
default_action: report
require_sla: true
default_sla_days: 14
escalation:
trigger: high-signal class or repeated finding
action: require issue + owner + due date
low:
action: report
codeql:
severity_mapping:
error: high_or_critical
warning: medium_or_lower
note: informational
blocking_levels:
- error
warning_policy:
default_action: report
escalation_high_signal_rule_ids:
- go/request-forgery
- js/missing-rate-limiting
- js/insecure-randomness
trivy:
blocking_severities:
- CRITICAL
- HIGH
medium_policy:
action: report
escalation: issue-with-sla
grype:
blocking_severities:
- Critical
- High
medium_policy:
action: report
escalation: issue-with-sla
enforcement_contract:
codeql_local_vs_ci: "local and ci block on codeql error-level findings only"
supply_chain_medium: "medium vulnerabilities are non-blocking by default and require explicit triage"
auth_regression_guard: "state-changing routes must remain protected by auth middleware"

View File

@@ -63,7 +63,7 @@ Agent Skills are self-documenting, AI-discoverable task definitions that combine
| Skill Name | Category | Description | Status |
|------------|----------|-------------|--------|
| [qa-precommit-all](./qa-precommit-all.SKILL.md) | qa | Run all pre-commit hooks on entire codebase | ✅ Active |
| [qa-lefthook-all](./qa-lefthook-all.SKILL.md) | qa | Run all lefthook pre-commitphase hooks on entire codebase | ✅ Active |
### Utility Skills

View File

@@ -20,12 +20,12 @@ jobs:
steps:
- name: Checkout Code
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Setup Go
uses: actions/setup-go@v5
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version: '1.23'
go-version: "1.26.2"
- name: Run GORM Security Scanner
id: gorm-scan
@@ -56,7 +56,7 @@ jobs:
- name: Comment on PR
if: always() && github.event_name == 'pull_request'
uses: actions/github-script@v7
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
const critical = ${{ steps.parse-report.outputs.critical }};
@@ -89,7 +89,7 @@ jobs:
- name: Upload GORM Scan Report
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: gorm-security-report-${{ github.run_id }}
path: docs/reports/gorm-scan-ci-*.txt

349
.github/skills/qa-lefthook-all.SKILL.md vendored Normal file
View File

@@ -0,0 +1,349 @@
---
# agentskills.io specification v1.0
name: "qa-lefthook-all"
version: "1.0.0"
description: "Run all lefthook pre-commit-phase hooks for comprehensive code quality validation"
author: "Charon Project"
license: "MIT"
tags:
- "qa"
- "quality"
- "pre-commit"
- "linting"
- "validation"
compatibility:
os:
- "linux"
- "darwin"
shells:
- "bash"
requirements:
- name: "python3"
version: ">=3.8"
optional: false
- name: "lefthook"
version: ">=0.14"
optional: false
environment_variables:
- name: "SKIP"
description: "Comma-separated list of hook IDs to skip"
default: ""
required: false
parameters:
- name: "files"
type: "string"
description: "Specific files to check (default: all staged files)"
default: "--all-files"
required: false
outputs:
- name: "validation_report"
type: "stdout"
description: "Results of all pre-commit hook executions"
- name: "exit_code"
type: "number"
description: "0 if all hooks pass, non-zero if any fail"
metadata:
category: "qa"
subcategory: "quality"
execution_time: "medium"
risk_level: "low"
ci_cd_safe: true
requires_network: false
idempotent: true
---
# QA Pre-commit All
## Overview
Executes all configured lefthook pre-commit-phase hooks to validate code quality, formatting, security, and best practices across the entire codebase. This skill runs checks for Python, Go, JavaScript/TypeScript, Markdown, YAML, and more.
This skill is designed for CI/CD pipelines and local quality validation before committing code.
## Prerequisites
- Python 3.8 or higher installed and in PATH
- Python virtual environment activated (`.venv`)
- Pre-commit installed in virtual environment: `pip install pre-commit`
- Pre-commit hooks installed: `pre-commit install`
- All language-specific tools installed (Go, Node.js, etc.)
## Usage
### Basic Usage
Run all pre-commit-phase hooks on all files:
```bash
cd /path/to/charon
lefthook run pre-commit
```
### Staged Files Only
Run lefthook on staged files only (faster):
```bash
lefthook run pre-commit --staged
```
### Specific Hook
Run only a specific hook by ID:
```bash
lefthook run pre-commit --hooks=trailing-whitespace
```
### Skip Specific Hooks
Skip certain hooks during execution:
```bash
SKIP=prettier,eslint .github/skills/scripts/skill-runner.sh qa-precommit-all
```
## Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| files | string | No | --all-files | File selection mode (--all-files or staged) |
## Environment Variables
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| SKIP | No | "" | Comma-separated hook IDs to skip |
| PRE_COMMIT_HOME | No | ~/.cache/pre-commit | Pre-commit cache directory |
## Outputs
- **Success Exit Code**: 0 (all hooks passed)
- **Error Exit Codes**: Non-zero (one or more hooks failed)
- **Output**: Detailed results from each hook
## Pre-commit Hooks Included
The following hooks are configured in `.pre-commit-config.yaml`:
### General Hooks
- **trailing-whitespace**: Remove trailing whitespace
- **end-of-file-fixer**: Ensure files end with newline
- **check-yaml**: Validate YAML syntax
- **check-json**: Validate JSON syntax
- **check-merge-conflict**: Detect merge conflict markers
- **check-added-large-files**: Prevent committing large files
### Python Hooks
- **black**: Code formatting
- **isort**: Import sorting
- **flake8**: Linting
- **mypy**: Type checking
### Go Hooks
- **gofmt**: Code formatting
- **go-vet**: Static analysis
- **golangci-lint**: Comprehensive linting
### JavaScript/TypeScript Hooks
- **prettier**: Code formatting
- **eslint**: Linting and code quality
### Markdown Hooks
- **markdownlint**: Markdown linting and formatting
### Security Hooks
- **detect-private-key**: Prevent committing private keys
- **detect-aws-credentials**: Prevent committing AWS credentials
## Examples
### Example 1: Full Quality Check
```bash
# Run all hooks on all files
source .venv/bin/activate
.github/skills/scripts/skill-runner.sh qa-precommit-all
```
Output:
```
Trim Trailing Whitespace.....................................Passed
Fix End of Files.............................................Passed
Check Yaml...................................................Passed
Check JSON...................................................Passed
Check for merge conflicts....................................Passed
Check for added large files..................................Passed
black........................................................Passed
isort........................................................Passed
prettier.....................................................Passed
eslint.......................................................Passed
markdownlint.................................................Passed
```
### Example 2: Quick Staged Files Check
```bash
# Run only on staged files (faster for pre-commit)
.github/skills/scripts/skill-runner.sh qa-precommit-all staged
```
### Example 3: Skip Slow Hooks
```bash
# Skip time-consuming hooks for quick validation
SKIP=golangci-lint,mypy .github/skills/scripts/skill-runner.sh qa-precommit-all
```
### Example 4: CI/CD Pipeline Integration
```yaml
# GitHub Actions example
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install pre-commit
run: pip install pre-commit
- name: Run QA Pre-commit Checks
run: .github/skills/scripts/skill-runner.sh qa-precommit-all
```
### Example 5: Auto-fix Mode
```bash
# Some hooks can auto-fix issues
# Run twice: first to fix, second to validate
.github/skills/scripts/skill-runner.sh qa-precommit-all || \
.github/skills/scripts/skill-runner.sh qa-precommit-all
```
## Error Handling
### Common Issues
**Virtual environment not activated**:
```bash
Error: pre-commit not found
Solution: source .venv/bin/activate
```
**Pre-commit not installed**:
```bash
Error: pre-commit command not available
Solution: pip install pre-commit
```
**Hooks not installed**:
```bash
Error: Run 'pre-commit install'
Solution: pre-commit install
```
**Hook execution failed**:
```bash
Hook X failed
Solution: Review error output and fix reported issues
```
**Language tool missing**:
```bash
Error: golangci-lint not found
Solution: Install required language tools
```
## Exit Codes
- **0**: All hooks passed
- **1**: One or more hooks failed
- **Other**: Hook execution error
## Hook Fixing Strategies
### Auto-fixable Issues
These hooks automatically fix issues:
- `trailing-whitespace`
- `end-of-file-fixer`
- `black`
- `isort`
- `prettier`
- `gofmt`
**Workflow**: Run pre-commit, review changes, commit fixed files
### Manual Fixes Required
These hooks only report issues:
- `check-yaml`
- `check-json`
- `flake8`
- `eslint`
- `markdownlint`
- `go-vet`
- `golangci-lint`
**Workflow**: Review errors, manually fix code, re-run pre-commit
## Related Skills
- [test-backend-coverage](./test-backend-coverage.SKILL.md) - Backend test coverage
- [test-frontend-coverage](./test-frontend-coverage.SKILL.md) - Frontend test coverage
- [security-scan-trivy](./security-scan-trivy.SKILL.md) - Security scanning
## Notes
- Pre-commit hooks cache their environments for faster execution
- First run may be slow while environments are set up
- Subsequent runs are much faster (seconds vs minutes)
- Hooks run in parallel where possible
- Failed hooks stop execution (fail-fast behavior)
- Use `SKIP` to bypass specific hooks temporarily
- Recommended to run before every commit
- Can be integrated into Git pre-commit hook for automatic checks
- Cache location: `~/.cache/pre-commit` (configurable)
## Performance Tips
- **Initial Setup**: First run takes longer (installing hook environments)
- **Incremental**: Run on staged files only for faster feedback
- **Parallel**: Pre-commit runs compatible hooks in parallel
- **Cache**: Hook environments are cached and reused
- **Skip**: Use `SKIP` to bypass slow hooks during development
## Integration with Git
To automatically run on every commit:
```bash
# Install Git pre-commit hook
pre-commit install
# Now pre-commit runs automatically on git commit
git commit -m "Your commit message"
```
To bypass pre-commit hook temporarily:
```bash
git commit --no-verify -m "Emergency commit"
```
## Configuration
Pre-commit configuration is in `.pre-commit-config.yaml`. To update hooks:
```bash
# Update to latest versions
pre-commit autoupdate
# Clean cache and re-install
pre-commit clean
pre-commit install --install-hooks
```
---
**Last Updated**: 2025-12-20
**Maintained by**: Charon Project
**Source**: `pre-commit run --all-files`

View File

@@ -1,8 +1,8 @@
---
# agentskills.io specification v1.0
name: "qa-precommit-all"
name: "qa-lefthook-all"
version: "1.0.0"
description: "Run all pre-commit hooks for comprehensive code quality validation"
description: "Run all lefthook pre-commit-phase hooks for comprehensive code quality validation"
author: "Charon Project"
license: "MIT"
tags:
@@ -21,15 +21,11 @@ requirements:
- name: "python3"
version: ">=3.8"
optional: false
- name: "pre-commit"
version: ">=2.0"
- name: "lefthook"
version: ">=0.14"
optional: false
environment_variables:
- name: "PRE_COMMIT_HOME"
description: "Pre-commit cache directory"
default: "~/.cache/pre-commit"
required: false
- name: "SKIP"
- name: "SKIP"
description: "Comma-separated list of hook IDs to skip"
default: ""
required: false
@@ -60,7 +56,7 @@ metadata:
## Overview
Executes all configured pre-commit hooks to validate code quality, formatting, security, and best practices across the entire codebase. This skill runs checks for Python, Go, JavaScript/TypeScript, Markdown, YAML, and more.
Executes all configured lefthook pre-commit-phase hooks to validate code quality, formatting, security, and best practices across the entire codebase. This skill runs checks for Python, Go, JavaScript/TypeScript, Markdown, YAML, and more.
This skill is designed for CI/CD pipelines and local quality validation before committing code.
@@ -76,19 +72,19 @@ This skill is designed for CI/CD pipelines and local quality validation before c
### Basic Usage
Run all hooks on all files:
Run all pre-commit-phase hooks on all files:
```bash
cd /path/to/charon
.github/skills/scripts/skill-runner.sh qa-precommit-all
lefthook run pre-commit
```
### Staged Files Only
Run hooks on staged files only (faster):
Run lefthook on staged files only (faster):
```bash
.github/skills/scripts/skill-runner.sh qa-precommit-all staged
lefthook run pre-commit --staged
```
### Specific Hook
@@ -96,7 +92,7 @@ Run hooks on staged files only (faster):
Run only a specific hook by ID:
```bash
SKIP="" .github/skills/scripts/skill-runner.sh qa-precommit-all trailing-whitespace
lefthook run pre-commit --hooks=trailing-whitespace
```
### Skip Specific Hooks

View File

@@ -192,6 +192,101 @@ get_project_root() {
return 1
}
# ensure_charon_encryption_key: Ensure CHARON_ENCRYPTION_KEY is present and valid
# for backend tests. Generates an ephemeral base64-encoded 32-byte key when
# missing or invalid.
ensure_charon_encryption_key() {
local key_source="existing"
local decoded_key_hex=""
local decoded_key_bytes=0
generate_key() {
if command -v openssl >/dev/null 2>&1; then
openssl rand -base64 32 | tr -d '\n'
return
fi
if command -v python3 >/dev/null 2>&1; then
python3 - <<'PY'
import base64
import os
print(base64.b64encode(os.urandom(32)).decode())
PY
return
fi
echo ""
}
if [[ -z "${CHARON_ENCRYPTION_KEY:-}" ]]; then
key_source="generated"
CHARON_ENCRYPTION_KEY="$(generate_key)"
fi
if [[ -z "${CHARON_ENCRYPTION_KEY:-}" ]]; then
if declare -f log_error >/dev/null 2>&1; then
log_error "Could not auto-provision CHARON_ENCRYPTION_KEY (requires openssl or python3)"
else
echo "[ERROR] Could not auto-provision CHARON_ENCRYPTION_KEY (requires openssl or python3)" >&2
fi
return 1
fi
if ! decoded_key_hex=$(printf '%s' "$CHARON_ENCRYPTION_KEY" | base64 --decode 2>/dev/null | od -An -tx1 -v | tr -d ' \n'); then
key_source="regenerated"
CHARON_ENCRYPTION_KEY="$(generate_key)"
if ! decoded_key_hex=$(printf '%s' "$CHARON_ENCRYPTION_KEY" | base64 --decode 2>/dev/null | od -An -tx1 -v | tr -d ' \n'); then
if declare -f log_error >/dev/null 2>&1; then
log_error "CHARON_ENCRYPTION_KEY is invalid and regeneration failed"
else
echo "[ERROR] CHARON_ENCRYPTION_KEY is invalid and regeneration failed" >&2
fi
return 1
fi
fi
decoded_key_bytes=$(( ${#decoded_key_hex} / 2 ))
if [[ "$decoded_key_bytes" -ne 32 ]]; then
key_source="regenerated"
CHARON_ENCRYPTION_KEY="$(generate_key)"
if ! decoded_key_hex=$(printf '%s' "$CHARON_ENCRYPTION_KEY" | base64 --decode 2>/dev/null | od -An -tx1 -v | tr -d ' \n'); then
if declare -f log_error >/dev/null 2>&1; then
log_error "CHARON_ENCRYPTION_KEY has invalid length and regeneration failed"
else
echo "[ERROR] CHARON_ENCRYPTION_KEY has invalid length and regeneration failed" >&2
fi
return 1
fi
decoded_key_bytes=$(( ${#decoded_key_hex} / 2 ))
if [[ "$decoded_key_bytes" -ne 32 ]]; then
if declare -f log_error >/dev/null 2>&1; then
log_error "Could not provision a valid 32-byte CHARON_ENCRYPTION_KEY"
else
echo "[ERROR] Could not provision a valid 32-byte CHARON_ENCRYPTION_KEY" >&2
fi
return 1
fi
fi
export CHARON_ENCRYPTION_KEY
if [[ "$key_source" == "generated" ]]; then
if declare -f log_info >/dev/null 2>&1; then
log_info "CHARON_ENCRYPTION_KEY not set; generated ephemeral test key"
fi
elif [[ "$key_source" == "regenerated" ]]; then
if declare -f log_warn >/dev/null 2>&1; then
log_warn "CHARON_ENCRYPTION_KEY invalid; generated ephemeral test key"
elif declare -f log_info >/dev/null 2>&1; then
log_info "CHARON_ENCRYPTION_KEY invalid; generated ephemeral test key"
fi
fi
return 0
}
# Export functions
export -f validate_go_environment
export -f validate_python_environment
@@ -200,3 +295,4 @@ export -f validate_docker_environment
export -f set_default_env
export -f validate_project_structure
export -f get_project_root
export -f ensure_charon_encryption_key

View File

@@ -95,6 +95,7 @@ run_codeql_scan() {
local source_root=$2
local db_name="codeql-db-${lang}"
local sarif_file="codeql-results-${lang}.sarif"
local suite=""
local build_mode_args=()
local codescanning_config="${PROJECT_ROOT}/.github/codeql/codeql-config.yml"
@@ -107,6 +108,9 @@ run_codeql_scan() {
if [[ "${lang}" == "javascript" ]]; then
build_mode_args=(--build-mode=none)
suite="codeql/javascript-queries:codeql-suites/javascript-security-and-quality.qls"
else
suite="codeql/go-queries:codeql-suites/go-security-and-quality.qls"
fi
log_step "CODEQL" "Scanning ${lang} code in ${source_root}/"
@@ -135,8 +139,9 @@ run_codeql_scan() {
fi
# Run analysis
log_info "Analyzing with Code Scanning config (CI-aligned query filters)..."
log_info "Analyzing with CI-aligned suite: ${suite}"
if ! codeql database analyze "${db_name}" \
"${suite}" \
--format=sarif-latest \
--output="${sarif_file}" \
--sarif-add-baseline-file-info \

View File

@@ -136,8 +136,8 @@ This skill uses the **security-and-quality** suite to match CI:
| Language | Suite | Queries | Coverage |
|----------|-------|---------|----------|
| Go | go-security-and-quality.qls | 61 | Security + quality issues |
| JavaScript | javascript-security-and-quality.qls | 204 | Security + quality issues |
| Go | go-security-and-quality.qls | version-dependent | Security + quality issues |
| JavaScript | javascript-security-and-quality.qls | version-dependent | Security + quality issues |
**Note:** This matches GitHub Actions CodeQL default configuration exactly.
@@ -251,7 +251,7 @@ Solution: Verify source-root points to correct directory
- [security-scan-trivy](./security-scan-trivy.SKILL.md) - Container/dependency vulnerabilities
- [security-scan-go-vuln](./security-scan-go-vuln.SKILL.md) - Go-specific CVE checking
- [qa-precommit-all](./qa-precommit-all.SKILL.md) - Pre-commit quality checks
- [qa-lefthook-all](./qa-lefthook-all.SKILL.md) - Lefthook pre-commit-phase quality checks
## CI Alignment
@@ -260,8 +260,7 @@ This skill is specifically designed to match GitHub Actions CodeQL workflow:
| Parameter | Local | CI | Aligned |
|-----------|-------|-----|---------|
| Query Suite | security-and-quality | security-and-quality | ✅ |
| Go Queries | 61 | 61 | ✅ |
| JS Queries | 204 | 204 | ✅ |
| Query Expansion | version-dependent | version-dependent | ✅ (when versions match) |
| Threading | auto | auto | ✅ |
| Baseline Info | enabled | enabled | ✅ |

View File

@@ -35,7 +35,7 @@ fi
# Check Grype
if ! command -v grype >/dev/null 2>&1; then
log_error "Grype not found - install from: https://github.com/anchore/grype"
log_error "Installation: curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin v0.107.0"
log_error "Installation: curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin v0.111.0"
error_exit "Grype is required for vulnerability scanning" 2
fi
@@ -50,8 +50,8 @@ SYFT_INSTALLED_VERSION=$(syft version | grep -oP 'Version:\s*\Kv?[0-9]+\.[0-9]+\
GRYPE_INSTALLED_VERSION=$(grype version | grep -oP 'Version:\s*\Kv?[0-9]+\.[0-9]+\.[0-9]+' | head -1 || echo "unknown")
# Set defaults matching CI workflow
set_default_env "SYFT_VERSION" "v1.17.0"
set_default_env "GRYPE_VERSION" "v0.107.0"
set_default_env "SYFT_VERSION" "v1.42.4"
set_default_env "GRYPE_VERSION" "v0.111.0"
set_default_env "IMAGE_TAG" "charon:local"
set_default_env "FAIL_ON_SEVERITY" "Critical,High"
@@ -139,7 +139,10 @@ log_info "This may take 30-60 seconds on first run (database download)"
# Run Grype against the SBOM (generated from image, not filesystem)
# This matches exactly what CI does in supply-chain-pr.yml
# --config ensures .grype.yaml ignore rules are applied, separating
# ignored matches from actionable ones in the JSON output
if grype sbom:sbom.cyclonedx.json \
--config .grype.yaml \
--output json \
--file grype-results.json; then
log_success "Vulnerability scan complete"
@@ -149,6 +152,7 @@ fi
# Generate SARIF output for GitHub Security (matches CI)
grype sbom:sbom.cyclonedx.json \
--config .grype.yaml \
--output sarif \
--file grype-results.sarif 2>/dev/null || true

View File

@@ -545,7 +545,7 @@ Solution: Add suppression comment: // gorm-scanner:ignore [reason]
- [security-scan-trivy](./security-scan-trivy.SKILL.md) - Container vulnerability scanning
- [security-scan-codeql](./security-scan-codeql.SKILL.md) - Static analysis for Go/JS
- [qa-precommit-all](./qa-precommit-all.SKILL.md) - Pre-commit quality checks
- [qa-lefthook-all](./qa-lefthook-all.SKILL.md) - Lefthook pre-commit-phase quality checks
## Best Practices

View File

@@ -26,6 +26,7 @@ validate_docker_environment || error_exit "Docker is required but not available"
# Set defaults
set_default_env "TRIVY_SEVERITY" "CRITICAL,HIGH,MEDIUM"
set_default_env "TRIVY_TIMEOUT" "10m"
set_default_env "TRIVY_DOCKER_RM" "true"
# Parse arguments
# Default scanners exclude misconfig to avoid non-actionable policy bundle issues
@@ -88,8 +89,19 @@ for d in "${SKIP_DIRS[@]}"; do
SKIP_DIR_FLAGS+=("--skip-dirs" "/app/${d}")
done
log_step "PREPARE" "Pulling latest Trivy Docker image"
if ! docker pull aquasec/trivy:latest >/dev/null; then
log_error "Failed to pull Docker image aquasec/trivy:latest"
exit 1
fi
# Run Trivy via Docker
if docker run --rm \
DOCKER_RUN_ARGS=(run)
if [[ "${TRIVY_DOCKER_RM}" == "true" ]]; then
DOCKER_RUN_ARGS+=(--rm)
fi
if docker "${DOCKER_RUN_ARGS[@]}" \
-v "$(pwd):/app:ro" \
-e "TRIVY_SEVERITY=${TRIVY_SEVERITY}" \
-e "TRIVY_TIMEOUT=${TRIVY_TIMEOUT}" \

View File

@@ -227,7 +227,7 @@ Solution: Review and remediate reported vulnerabilities
## Related Skills
- [security-scan-go-vuln](./security-scan-go-vuln.SKILL.md) - Go-specific vulnerability checking
- [qa-precommit-all](./qa-precommit-all.SKILL.md) - Pre-commit quality checks
- [qa-lefthook-all](./qa-lefthook-all.SKILL.md) - Lefthook pre-commit-phase quality checks
## Notes

View File

@@ -32,7 +32,7 @@ cd "${PROJECT_ROOT}"
validate_project_structure "backend" "scripts/go-test-coverage.sh" || error_exit "Invalid project structure"
# Set default environment variables
set_default_env "CHARON_MIN_COVERAGE" "85"
set_default_env "CHARON_MIN_COVERAGE" "87"
set_default_env "PERF_MAX_MS_GETSTATUS_P95" "25ms"
set_default_env "PERF_MAX_MS_GETSTATUS_P95_PARALLEL" "50ms"
set_default_env "PERF_MAX_MS_LISTDECISIONS_P95" "75ms"

View File

@@ -25,6 +25,10 @@ requirements:
version: ">=3.8"
optional: false
environment_variables:
- name: "CHARON_ENCRYPTION_KEY"
description: "Encryption key for backend test runtime. Auto-generated ephemerally by the script if missing/invalid."
default: "(auto-generated for test run)"
required: false
- name: "CHARON_MIN_COVERAGE"
description: "Minimum coverage percentage required (overrides default)"
default: "85"
@@ -125,6 +129,7 @@ For use in GitHub Actions or other CI/CD pipelines:
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| CHARON_ENCRYPTION_KEY | No | auto-generated for test run | Backend test encryption key. If missing/invalid, an ephemeral 32-byte base64 key is generated for the run. |
| CHARON_MIN_COVERAGE | No | 85 | Minimum coverage percentage required for success |
| CPM_MIN_COVERAGE | No | 85 | Legacy name for minimum coverage (fallback) |
| PERF_MAX_MS_GETSTATUS_P95 | No | 25ms | Max P95 latency for GetStatus endpoint |

View File

@@ -11,10 +11,13 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Helper scripts are in .github/skills/scripts/
SKILLS_SCRIPTS_DIR="$(cd "${SCRIPT_DIR}/../scripts" && pwd)"
# shellcheck disable=SC1091
# shellcheck source=../scripts/_logging_helpers.sh
source "${SKILLS_SCRIPTS_DIR}/_logging_helpers.sh"
# shellcheck disable=SC1091
# shellcheck source=../scripts/_error_handling_helpers.sh
source "${SKILLS_SCRIPTS_DIR}/_error_handling_helpers.sh"
# shellcheck disable=SC1091
# shellcheck source=../scripts/_environment_helpers.sh
source "${SKILLS_SCRIPTS_DIR}/_environment_helpers.sh"
@@ -24,6 +27,7 @@ PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
# Validate environment
log_step "ENVIRONMENT" "Validating prerequisites"
validate_go_environment "1.23" || error_exit "Go 1.23+ is required"
ensure_charon_encryption_key || error_exit "Failed to provision CHARON_ENCRYPTION_KEY for backend tests"
# Validate project structure
log_step "VALIDATION" "Checking project structure"

View File

@@ -21,7 +21,11 @@ requirements:
- name: "go"
version: ">=1.23"
optional: false
environment_variables: []
environment_variables:
- name: "CHARON_ENCRYPTION_KEY"
description: "Encryption key for backend test runtime. Auto-generated ephemerally if missing/invalid."
default: "(auto-generated for test run)"
required: false
parameters:
- name: "verbose"
type: "boolean"
@@ -106,7 +110,9 @@ For use in GitHub Actions or other CI/CD pipelines:
## Environment Variables
No environment variables are required for this skill.
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| CHARON_ENCRYPTION_KEY | No | auto-generated for test run | Backend test encryption key. If missing/invalid, an ephemeral 32-byte base64 key is generated for the run. |
## Outputs

View File

@@ -32,7 +32,7 @@ cd "${PROJECT_ROOT}"
validate_project_structure "frontend" "scripts/frontend-test-coverage.sh" || error_exit "Invalid project structure"
# Set default environment variables
set_default_env "CHARON_MIN_COVERAGE" "85"
set_default_env "CHARON_MIN_COVERAGE" "87"
# Execute the legacy script
log_step "EXECUTION" "Running frontend tests with coverage"

View File

@@ -8,6 +8,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event.issue.number || github.event.pull_request.number }}
cancel-in-progress: false
permissions:
contents: read
jobs:
add-to-project:
runs-on: ubuntu-latest

View File

@@ -12,6 +12,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.workflow_run.head_branch || github.head_ref || github.ref_name }}
cancel-in-progress: true
permissions:
contents: write
jobs:
update-draft:
runs-on: ubuntu-latest
@@ -21,6 +24,6 @@ jobs:
with:
ref: ${{ github.event.workflow_run.head_sha || github.sha }}
- name: Draft Release
uses: release-drafter/release-drafter@6db134d15f3909ccc9eefd369f02bd1e9cffdf97 # v6
uses: release-drafter/release-drafter@5de93583980a40bd78603b6dfdcda5b4df377b32 # v7
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -8,6 +8,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event.issue.number }}
cancel-in-progress: true
permissions:
contents: read
jobs:
auto-label:
runs-on: ubuntu-latest
@@ -15,7 +18,7 @@ jobs:
issues: write
steps:
- name: Auto-label based on title and body
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
const issue = context.payload.issue;

View File

@@ -33,7 +33,7 @@ jobs:
- name: Calculate Semantic Version
id: semver
uses: paulhatch/semantic-version@f29500c9d60a99ed5168e39ee367e0976884c46e # v6.0.1
uses: paulhatch/semantic-version@9f72830310d5ed81233b641ee59253644cd8a8fc # v6.0.2
with:
# The prefix to use to create tags
tag_prefix: "v"
@@ -89,7 +89,7 @@ jobs:
- name: Create GitHub Release (creates tag via API)
if: ${{ steps.semver.outputs.changed == 'true' && steps.check_release.outputs.exists == 'false' }}
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3
with:
tag_name: ${{ steps.determine_tag.outputs.tag }}
name: Release ${{ steps.determine_tag.outputs.tag }}

View File

@@ -1,54 +0,0 @@
name: "Badge: GHCR downloads"
on:
schedule:
# Update periodically (GitHub schedules may be delayed)
- cron: '17 * * * *'
workflow_dispatch: {}
permissions:
contents: write
packages: read
concurrency:
group: ghcr-downloads-badge
cancel-in-progress: false
jobs:
update:
runs-on: ubuntu-latest
steps:
- name: Checkout (main)
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: main
- name: Set up Node
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
with:
node-version: 24.13.1
- name: Update GHCR downloads badge
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GHCR_OWNER: ${{ github.repository_owner }}
GHCR_PACKAGE: charon
BADGE_OUTPUT: .github/badges/ghcr-downloads.json
run: node scripts/update-ghcr-downloads-badge.mjs
- name: Commit and push (if changed)
shell: bash
run: |
set -euo pipefail
if git diff --quiet; then
echo "No changes."
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add .github/badges/ghcr-downloads.json
git commit -m "chore(badges): update GHCR downloads [skip ci]"
git push origin HEAD:main

View File

@@ -3,6 +3,8 @@ name: Go Benchmark
on:
pull_request:
push:
branches:
- main
workflow_dispatch:
concurrency:
@@ -10,7 +12,7 @@ concurrency:
cancel-in-progress: true
env:
GO_VERSION: '1.26.0'
GO_VERSION: '1.26.2'
GOTOOLCHAIN: auto
# Minimal permissions at workflow level; write permissions granted at job level for push only
@@ -33,9 +35,10 @@ jobs:
ref: ${{ github.event.workflow_run.head_sha || github.sha }}
- name: Set up Go
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: backend/go.sum
- name: Run Benchmark
@@ -49,7 +52,7 @@ jobs:
# This avoids gh-pages branch errors and permission issues on fork PRs
if: github.event.workflow_run.event == 'push' && github.event.workflow_run.head_branch == 'main'
# Security: Pinned to full SHA for supply chain security
uses: benchmark-action/github-action-benchmark@4e0b38bc48375986542b13c0d8976b7b80c60c00 # v1
uses: benchmark-action/github-action-benchmark@a60cea5bc7b49e15c1f58f411161f99e0df48372 # v1.22.0
with:
name: Go Benchmark
tool: 'go'

View File

@@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check for Caddy v3 and open issue
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
const upstream = { owner: 'caddyserver', repo: 'caddy' };

View File

@@ -20,6 +20,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event.workflow_run.event || github.event_name }}-${{ github.event.workflow_run.head_branch || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
cerberus-integration:
name: Cerberus Security Stack Integration
@@ -31,7 +34,7 @@ jobs:
- name: Build Docker image (Local)
run: |
echo "Building image locally for integration tests..."
docker build -t charon:local .
docker build -t charon:local --build-arg CI="${CI:-false}" .
echo "✅ Successfully built charon:local"
- name: Run Cerberus integration tests

View File

@@ -3,6 +3,8 @@ name: Upload Coverage to Codecov
on:
pull_request:
push:
branches:
- main
workflow_dispatch:
inputs:
run_backend:
@@ -17,11 +19,11 @@ on:
type: boolean
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.run_id }}
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
GO_VERSION: '1.26.0'
GO_VERSION: '1.26.2'
NODE_VERSION: '24.12.0'
GOTOOLCHAIN: auto
@@ -43,9 +45,10 @@ jobs:
ref: ${{ github.sha }}
- name: Set up Go
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: backend/go.sum
# SECURITY: Keep pull_request (not pull_request_target) for secret-bearing backend tests.
@@ -123,6 +126,9 @@ jobs:
echo "__CHARON_EOF__"
} >> "$GITHUB_ENV"
- name: Install gotestsum
run: go install gotest.tools/gotestsum@v1.13.0
- name: Run Go tests with coverage
working-directory: ${{ github.workspace }}
env:
@@ -131,8 +137,16 @@ jobs:
bash scripts/go-test-coverage.sh 2>&1 | tee backend/test-output.txt
exit "${PIPESTATUS[0]}"
- name: Upload test output artifact
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: backend-test-output
path: backend/test-output.txt
retention-days: 7
- name: Upload backend coverage to Codecov
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./backend/coverage.txt
@@ -152,7 +166,7 @@ jobs:
ref: ${{ github.sha }}
- name: Set up Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
@@ -169,7 +183,7 @@ jobs:
exit "${PIPESTATUS[0]}"
- name: Upload frontend coverage to Codecov
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6
with:
token: ${{ secrets.CODECOV_TOKEN }}
directory: ./frontend/coverage

View File

@@ -4,7 +4,7 @@ on:
pull_request:
branches: [main, nightly, development]
push:
branches: [main, nightly, development, 'feature/**', 'fix/**']
branches: [main]
workflow_dispatch:
schedule:
- cron: '0 3 * * 1' # Mondays 03:00 UTC
@@ -15,6 +15,7 @@ concurrency:
env:
GOTOOLCHAIN: auto
GO_VERSION: '1.26.2'
permissions:
contents: read
@@ -39,14 +40,19 @@ jobs:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: ${{ github.sha }}
# Use github.ref (full ref path) instead of github.ref_name:
# - push/schedule: resolves to refs/heads/<branch>, checking out latest HEAD
# - pull_request: resolves to refs/pull/<n>/merge, the correct PR merge ref
# github.ref_name fails for PRs because it yields "<n>/merge" which checkout
# interprets as a branch name (refs/heads/<n>/merge) that does not exist.
ref: ${{ github.ref }}
- name: Verify CodeQL parity guard
if: matrix.language == 'go'
run: bash scripts/ci/check-codeql-parity.sh
- name: Initialize CodeQL
uses: github/codeql-action/init@9e907b5e64f6b83e7804b09294d44122997950d6 # v4
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: ${{ matrix.language }}
queries: security-and-quality
@@ -57,9 +63,9 @@ jobs:
- name: Setup Go
if: matrix.language == 'go'
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version: 1.26.0
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: backend/go.sum
- name: Verify Go toolchain and build
@@ -86,10 +92,10 @@ jobs:
run: mkdir -p sarif-results
- name: Autobuild
uses: github/codeql-action/autobuild@9e907b5e64f6b83e7804b09294d44122997950d6 # v4
uses: github/codeql-action/autobuild@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@9e907b5e64f6b83e7804b09294d44122997950d6 # v4
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
category: "/language:${{ matrix.language }}"
output: sarif-results/${{ matrix.language }}
@@ -122,10 +128,28 @@ jobs:
exit 1
fi
# shellcheck disable=SC2016
EFFECTIVE_LEVELS_JQ='[
.runs[] as $run
| $run.results[]
| . as $result
| ($run.tool.driver.rules // []) as $rules
| ((
$result.level
// (if (($result.ruleIndex | type) == "number") then ($rules[$result.ruleIndex].defaultConfiguration.level // empty) else empty end)
// ([
$rules[]?
| select((.id // "") == ($result.ruleId // ""))
| (.defaultConfiguration.level // empty)
][0] // empty)
// ""
) | ascii_downcase)
]'
echo "Found SARIF file: $SARIF_FILE"
ERROR_COUNT=$(jq '[.runs[].results[] | select(.level == "error")] | length' "$SARIF_FILE")
WARNING_COUNT=$(jq '[.runs[].results[] | select(.level == "warning")] | length' "$SARIF_FILE")
NOTE_COUNT=$(jq '[.runs[].results[] | select(.level == "note")] | length' "$SARIF_FILE")
ERROR_COUNT=$(jq -r "${EFFECTIVE_LEVELS_JQ} | map(select(. == \"error\")) | length" "$SARIF_FILE")
WARNING_COUNT=$(jq -r "${EFFECTIVE_LEVELS_JQ} | map(select(. == \"warning\")) | length" "$SARIF_FILE")
NOTE_COUNT=$(jq -r "${EFFECTIVE_LEVELS_JQ} | map(select(. == \"note\")) | length" "$SARIF_FILE")
{
echo "**Findings:**"
@@ -135,14 +159,32 @@ jobs:
echo ""
if [ "$ERROR_COUNT" -gt 0 ]; then
echo "❌ **CRITICAL:** High-severity security issues found!"
echo "❌ **BLOCKING:** CodeQL error-level security issues found"
echo ""
echo "### Top Issues:"
echo '```'
jq -r '.runs[].results[] | select(.level == "error") | "\(.ruleId): \(.message.text)"' "$SARIF_FILE" | head -5
# shellcheck disable=SC2016
jq -r '
.runs[] as $run
| $run.results[]
| . as $result
| ($run.tool.driver.rules // []) as $rules
| ((
$result.level
// (if (($result.ruleIndex | type) == "number") then ($rules[$result.ruleIndex].defaultConfiguration.level // empty) else empty end)
// ([
$rules[]?
| select((.id // "") == ($result.ruleId // ""))
| (.defaultConfiguration.level // empty)
][0] // empty)
// ""
) | ascii_downcase) as $effectiveLevel
| select($effectiveLevel == "error")
| "\($effectiveLevel): \($result.ruleId // \"<unknown-rule>\"): \($result.message.text)"
' "$SARIF_FILE" | head -5
echo '```'
else
echo "✅ No high-severity issues found"
echo "✅ No blocking CodeQL issues found"
fi
} >> "$GITHUB_STEP_SUMMARY"
@@ -169,9 +211,26 @@ jobs:
exit 1
fi
ERROR_COUNT=$(jq '[.runs[].results[] | select(.level == "error")] | length' "$SARIF_FILE")
# shellcheck disable=SC2016
ERROR_COUNT=$(jq -r '[
.runs[] as $run
| $run.results[]
| . as $result
| ($run.tool.driver.rules // []) as $rules
| ((
$result.level
// (if (($result.ruleIndex | type) == "number") then ($rules[$result.ruleIndex].defaultConfiguration.level // empty) else empty end)
// ([
$rules[]?
| select((.id // "") == ($result.ruleId // ""))
| (.defaultConfiguration.level // empty)
][0] // empty)
// ""
) | ascii_downcase) as $effectiveLevel
| select($effectiveLevel == "error")
] | length' "$SARIF_FILE")
if [ "$ERROR_COUNT" -gt 0 ]; then
echo "::error::CodeQL found $ERROR_COUNT high-severity security issues. Fix before merging."
echo "::error::CodeQL found $ERROR_COUNT blocking findings (effective-level=error). Fix before merging. Policy: .github/security-severity-policy.yml"
exit 1
fi

View File

@@ -5,10 +5,6 @@ on:
- cron: '0 3 * * 0' # Weekly: Sundays at 03:00 UTC
workflow_dispatch:
inputs:
registries:
description: 'Comma-separated registries to prune (ghcr,dockerhub)'
required: false
default: 'ghcr,dockerhub'
keep_days:
description: 'Number of days to retain images (unprotected)'
required: false
@@ -27,16 +23,17 @@ permissions:
contents: read
jobs:
prune:
prune-ghcr:
runs-on: ubuntu-latest
env:
OWNER: ${{ github.repository_owner }}
IMAGE_NAME: charon
REGISTRIES: ${{ github.event.inputs.registries || 'ghcr,dockerhub' }}
KEEP_DAYS: ${{ github.event.inputs.keep_days || '30' }}
KEEP_LAST_N: ${{ github.event.inputs.keep_last_n || '30' }}
DRY_RUN: ${{ github.event.inputs.dry_run || 'false' }}
PROTECTED_REGEX: '["^v","^latest$","^main$","^develop$"]'
DRY_RUN: ${{ github.event_name == 'pull_request' && 'true' || github.event.inputs.dry_run || 'false' }}
PROTECTED_REGEX: '["^v?[0-9]+\\.[0-9]+\\.[0-9]+$","^latest$","^main$","^develop$"]'
PRUNE_UNTAGGED: 'true'
PRUNE_SBOM_TAGS: 'true'
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
@@ -45,21 +42,19 @@ jobs:
run: |
sudo apt-get update && sudo apt-get install -y jq curl
- name: Run container prune
- name: Run GHCR prune
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
run: |
chmod +x scripts/prune-container-images.sh
./scripts/prune-container-images.sh 2>&1 | tee prune-${{ github.run_id }}.log
chmod +x scripts/prune-ghcr.sh
./scripts/prune-ghcr.sh 2>&1 | tee prune-ghcr-${{ github.run_id }}.log
- name: Summarize prune results (space reclaimed)
if: ${{ always() }}
- name: Summarize GHCR results
if: always()
run: |
set -euo pipefail
SUMMARY_FILE=prune-summary.env
LOG_FILE=prune-${{ github.run_id }}.log
SUMMARY_FILE=prune-summary-ghcr.env
LOG_FILE=prune-ghcr-${{ github.run_id }}.log
human() {
local bytes=${1:-0}
@@ -67,7 +62,7 @@ jobs:
echo "0 B"
return
fi
awk -v b="$bytes" 'function human(x){ split("B KiB MiB GiB TiB",u," "); i=0; while(x>1024){x/=1024;i++} printf "%0.2f %s", x, u[i+1]} END{human(b)}'
awk -v b="$bytes" 'BEGIN { split("B KiB MiB GiB TiB",u," "); i=0; x=b; while(x>1024){x/=1024;i++} printf "%0.2f %s", x, u[i+1] }'
}
if [ -f "$SUMMARY_FILE" ]; then
@@ -77,34 +72,155 @@ jobs:
TOTAL_DELETED_BYTES=$(grep -E '^TOTAL_DELETED_BYTES=' "$SUMMARY_FILE" | cut -d= -f2 || echo 0)
{
echo "## Container prune summary"
echo "## GHCR prune summary"
echo "- candidates: ${TOTAL_CANDIDATES} (≈ $(human "${TOTAL_CANDIDATES_BYTES}"))"
echo "- deleted: ${TOTAL_DELETED} (≈ $(human "${TOTAL_DELETED_BYTES}"))"
} >> "$GITHUB_STEP_SUMMARY"
printf 'PRUNE_SUMMARY: candidates=%s candidates_bytes=%s deleted=%s deleted_bytes=%s\n' \
"${TOTAL_CANDIDATES}" "${TOTAL_CANDIDATES_BYTES}" "${TOTAL_DELETED}" "${TOTAL_DELETED_BYTES}"
echo "Deleted approximately: $(human "${TOTAL_DELETED_BYTES}")"
echo "space_saved=$(human "${TOTAL_DELETED_BYTES}")" >> "$GITHUB_OUTPUT"
else
deleted_bytes=$(grep -oE '\( *approx +[0-9]+ bytes\)' "$LOG_FILE" | sed -E 's/.*approx +([0-9]+) bytes.*/\1/' | awk '{s+=$1} END {print s+0}' || true)
deleted_count=$(grep -cE 'deleting |DRY RUN: would delete' "$LOG_FILE" || true)
{
echo "## Container prune summary"
echo "## GHCR prune summary"
echo "- deleted (approx): ${deleted_count} (≈ $(human "${deleted_bytes}"))"
} >> "$GITHUB_STEP_SUMMARY"
printf 'PRUNE_SUMMARY: deleted_approx=%s deleted_bytes=%s\n' "${deleted_count}" "${deleted_bytes}"
echo "Deleted approximately: $(human "${deleted_bytes}")"
echo "space_saved=$(human "${deleted_bytes}")" >> "$GITHUB_OUTPUT"
fi
- name: Upload prune artifacts
if: ${{ always() }}
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- name: Upload GHCR prune artifacts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: prune-log-${{ github.run_id }}
name: prune-ghcr-log-${{ github.run_id }}
path: |
prune-${{ github.run_id }}.log
prune-summary.env
prune-ghcr-${{ github.run_id }}.log
prune-summary-ghcr.env
prune-dockerhub:
runs-on: ubuntu-latest
env:
OWNER: ${{ github.repository_owner }}
IMAGE_NAME: charon
KEEP_DAYS: ${{ github.event.inputs.keep_days || '30' }}
KEEP_LAST_N: ${{ github.event.inputs.keep_last_n || '30' }}
DRY_RUN: ${{ github.event_name == 'pull_request' && 'true' || github.event.inputs.dry_run || 'false' }}
PROTECTED_REGEX: '["^v?[0-9]+\\.[0-9]+\\.[0-9]+$","^latest$","^main$","^develop$"]'
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Install tools
run: |
sudo apt-get update && sudo apt-get install -y jq curl
- name: Run Docker Hub prune
env:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
run: |
chmod +x scripts/prune-dockerhub.sh
./scripts/prune-dockerhub.sh 2>&1 | tee prune-dockerhub-${{ github.run_id }}.log
- name: Summarize Docker Hub results
if: always()
run: |
set -euo pipefail
SUMMARY_FILE=prune-summary-dockerhub.env
LOG_FILE=prune-dockerhub-${{ github.run_id }}.log
human() {
local bytes=${1:-0}
if [ -z "$bytes" ] || [ "$bytes" -eq 0 ]; then
echo "0 B"
return
fi
awk -v b="$bytes" 'BEGIN { split("B KiB MiB GiB TiB",u," "); i=0; x=b; while(x>1024){x/=1024;i++} printf "%0.2f %s", x, u[i+1] }'
}
if [ -f "$SUMMARY_FILE" ]; then
TOTAL_CANDIDATES=$(grep -E '^TOTAL_CANDIDATES=' "$SUMMARY_FILE" | cut -d= -f2 || echo 0)
TOTAL_CANDIDATES_BYTES=$(grep -E '^TOTAL_CANDIDATES_BYTES=' "$SUMMARY_FILE" | cut -d= -f2 || echo 0)
TOTAL_DELETED=$(grep -E '^TOTAL_DELETED=' "$SUMMARY_FILE" | cut -d= -f2 || echo 0)
TOTAL_DELETED_BYTES=$(grep -E '^TOTAL_DELETED_BYTES=' "$SUMMARY_FILE" | cut -d= -f2 || echo 0)
{
echo "## Docker Hub prune summary"
echo "- candidates: ${TOTAL_CANDIDATES} (≈ $(human "${TOTAL_CANDIDATES_BYTES}"))"
echo "- deleted: ${TOTAL_DELETED} (≈ $(human "${TOTAL_DELETED_BYTES}"))"
} >> "$GITHUB_STEP_SUMMARY"
else
deleted_bytes=$(grep -oE '\( *approx +[0-9]+ bytes\)' "$LOG_FILE" | sed -E 's/.*approx +([0-9]+) bytes.*/\1/' | awk '{s+=$1} END {print s+0}' || true)
deleted_count=$(grep -cE 'deleting |DRY RUN: would delete' "$LOG_FILE" || true)
{
echo "## Docker Hub prune summary"
echo "- deleted (approx): ${deleted_count} (≈ $(human "${deleted_bytes}"))"
} >> "$GITHUB_STEP_SUMMARY"
fi
- name: Upload Docker Hub prune artifacts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: prune-dockerhub-log-${{ github.run_id }}
path: |
prune-dockerhub-${{ github.run_id }}.log
prune-summary-dockerhub.env
summarize:
runs-on: ubuntu-latest
needs: [prune-ghcr, prune-dockerhub]
if: always()
steps:
- name: Download all artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
pattern: prune-*-log-${{ github.run_id }}
merge-multiple: true
- name: Combined summary
run: |
set -euo pipefail
human() {
local bytes=${1:-0}
if [ -z "$bytes" ] || [ "$bytes" -eq 0 ]; then
echo "0 B"
return
fi
awk -v b="$bytes" 'BEGIN { split("B KiB MiB GiB TiB",u," "); i=0; x=b; while(x>1024){x/=1024;i++} printf "%0.2f %s", x, u[i+1] }'
}
GHCR_CANDIDATES=0 GHCR_CANDIDATES_BYTES=0 GHCR_DELETED=0 GHCR_DELETED_BYTES=0
if [ -f prune-summary-ghcr.env ]; then
GHCR_CANDIDATES=$(grep -E '^TOTAL_CANDIDATES=' prune-summary-ghcr.env | cut -d= -f2 || echo 0)
GHCR_CANDIDATES_BYTES=$(grep -E '^TOTAL_CANDIDATES_BYTES=' prune-summary-ghcr.env | cut -d= -f2 || echo 0)
GHCR_DELETED=$(grep -E '^TOTAL_DELETED=' prune-summary-ghcr.env | cut -d= -f2 || echo 0)
GHCR_DELETED_BYTES=$(grep -E '^TOTAL_DELETED_BYTES=' prune-summary-ghcr.env | cut -d= -f2 || echo 0)
fi
HUB_CANDIDATES=0 HUB_CANDIDATES_BYTES=0 HUB_DELETED=0 HUB_DELETED_BYTES=0
if [ -f prune-summary-dockerhub.env ]; then
HUB_CANDIDATES=$(grep -E '^TOTAL_CANDIDATES=' prune-summary-dockerhub.env | cut -d= -f2 || echo 0)
HUB_CANDIDATES_BYTES=$(grep -E '^TOTAL_CANDIDATES_BYTES=' prune-summary-dockerhub.env | cut -d= -f2 || echo 0)
HUB_DELETED=$(grep -E '^TOTAL_DELETED=' prune-summary-dockerhub.env | cut -d= -f2 || echo 0)
HUB_DELETED_BYTES=$(grep -E '^TOTAL_DELETED_BYTES=' prune-summary-dockerhub.env | cut -d= -f2 || echo 0)
fi
TOTAL_CANDIDATES=$((GHCR_CANDIDATES + HUB_CANDIDATES))
TOTAL_CANDIDATES_BYTES=$((GHCR_CANDIDATES_BYTES + HUB_CANDIDATES_BYTES))
TOTAL_DELETED=$((GHCR_DELETED + HUB_DELETED))
TOTAL_DELETED_BYTES=$((GHCR_DELETED_BYTES + HUB_DELETED_BYTES))
{
echo "## Combined container prune summary"
echo ""
echo "| Registry | Candidates | Deleted | Space Reclaimed |"
echo "|----------|------------|---------|-----------------|"
echo "| GHCR | ${GHCR_CANDIDATES} | ${GHCR_DELETED} | $(human "${GHCR_DELETED_BYTES}") |"
echo "| Docker Hub | ${HUB_CANDIDATES} | ${HUB_DELETED} | $(human "${HUB_DELETED_BYTES}") |"
echo "| **Total** | **${TOTAL_CANDIDATES}** | **${TOTAL_DELETED}** | **$(human "${TOTAL_DELETED_BYTES}")** |"
} >> "$GITHUB_STEP_SUMMARY"
printf 'PRUNE_SUMMARY: candidates=%s candidates_bytes=%s deleted=%s deleted_bytes=%s\n' \
"${TOTAL_CANDIDATES}" "${TOTAL_CANDIDATES_BYTES}" "${TOTAL_DELETED}" "${TOTAL_DELETED_BYTES}"
echo "Total space reclaimed: $(human "${TOTAL_DELETED_BYTES}")"

View File

@@ -8,6 +8,9 @@ concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
permissions:
contents: read
jobs:
create-labels:
runs-on: ubuntu-latest
@@ -15,7 +18,7 @@ jobs:
issues: write
steps:
- name: Create all project labels
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
const labels = [

View File

@@ -20,6 +20,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event.workflow_run.event || github.event_name }}-${{ github.event.workflow_run.head_branch || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
crowdsec-integration:
name: CrowdSec Bouncer Integration
@@ -31,7 +34,7 @@ jobs:
- name: Build Docker image (Local)
run: |
echo "Building image locally for integration tests..."
docker build -t charon:local .
docker build -t charon:local --build-arg CI="${CI:-false}" .
echo "✅ Successfully built charon:local"
- name: Run CrowdSec integration tests

View File

@@ -23,12 +23,19 @@ name: Docker Build, Publish & Test
on:
pull_request:
push:
branches: [main, development]
workflow_dispatch:
workflow_run:
workflows: ["Docker Lint"]
types: [completed]
concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_branch || github.head_ref || github.ref_name }}
cancel-in-progress: true
permissions:
contents: read
env:
GHCR_REGISTRY: ghcr.io
DOCKERHUB_REGISTRY: docker.io
@@ -38,7 +45,7 @@ env:
TRIGGER_HEAD_SHA: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.sha }}
TRIGGER_REF: ${{ github.event_name == 'workflow_run' && format('refs/heads/{0}', github.event.workflow_run.head_branch) || github.ref }}
TRIGGER_HEAD_REF: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_branch || github.head_ref }}
TRIGGER_PR_NUMBER: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.pull_requests[0].number || github.event.pull_request.number }}
TRIGGER_PR_NUMBER: ${{ github.event_name == 'workflow_run' && join(github.event.workflow_run.pull_requests.*.number, '') || format('{0}', github.event.pull_request.number) }}
TRIGGER_ACTOR: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.actor.login || github.actor }}
jobs:
@@ -111,21 +118,22 @@ jobs:
- name: Set up QEMU
if: steps.skip.outputs.skip_build != 'true'
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- name: Set up Docker Buildx
if: steps.skip.outputs.skip_build != 'true'
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Resolve Alpine base image digest
if: steps.skip.outputs.skip_build != 'true'
id: caddy
id: alpine
run: |
docker pull alpine:3.23.3
DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' alpine:3.23.3)
ALPINE_TAG=$(grep -m1 'ARG ALPINE_IMAGE=' Dockerfile | sed 's/ARG ALPINE_IMAGE=alpine://' | cut -d'@' -f1)
docker pull "alpine:${ALPINE_TAG}"
DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "alpine:${ALPINE_TAG}")
echo "image=$DIGEST" >> "$GITHUB_OUTPUT"
- name: Log in to GitHub Container Registry
if: steps.skip.outputs.skip_build != 'true'
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ${{ env.GHCR_REGISTRY }}
username: ${{ github.actor }}
@@ -133,7 +141,7 @@ jobs:
- name: Log in to Docker Hub
if: steps.skip.outputs.skip_build != 'true' && env.HAS_DOCKERHUB_TOKEN == 'true'
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: docker.io
username: ${{ secrets.DOCKERHUB_USERNAME }}
@@ -195,7 +203,7 @@ jobs:
- name: Generate Docker metadata
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
with:
images: |
${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}
@@ -229,7 +237,7 @@ jobs:
- name: Build and push Docker image (with retry)
if: steps.skip.outputs.skip_build != 'true'
id: build-and-push
uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
with:
timeout_minutes: 25
max_attempts: 3
@@ -267,7 +275,7 @@ jobs:
--build-arg "VERSION=${{ steps.meta.outputs.version }}"
--build-arg "BUILD_DATE=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}"
--build-arg "VCS_REF=${{ env.TRIGGER_HEAD_SHA }}"
--build-arg "CADDY_IMAGE=${{ steps.caddy.outputs.image }}"
--build-arg "ALPINE_IMAGE=${{ steps.alpine.outputs.image }}"
--iidfile /tmp/image-digest.txt
.
)
@@ -339,7 +347,7 @@ jobs:
- name: Upload Image Artifact
if: success() && steps.skip.outputs.skip_build != 'true' && env.TRIGGER_EVENT == 'pull_request'
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ env.TRIGGER_EVENT == 'pull_request' && format('pr-image-{0}', env.TRIGGER_PR_NUMBER) || 'push-image' }}
path: /tmp/charon-pr-image.tar
@@ -527,23 +535,25 @@ jobs:
- name: Run Trivy scan (table output)
if: env.TRIGGER_EVENT != 'pull_request' && steps.skip.outputs.skip_build != 'true' && steps.skip.outputs.is_feature_push != 'true'
uses: aquasecurity/trivy-action@c1824fd6edce30d7ab345a9989de00bbd46ef284 # 0.34.0
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 0.35.0
with:
image-ref: ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build-and-push.outputs.digest }}
format: 'table'
severity: 'CRITICAL,HIGH'
exit-code: '0'
version: 'v0.70.0'
continue-on-error: true
- name: Run Trivy vulnerability scanner (SARIF)
if: env.TRIGGER_EVENT != 'pull_request' && steps.skip.outputs.skip_build != 'true' && steps.skip.outputs.is_feature_push != 'true'
id: trivy
uses: aquasecurity/trivy-action@c1824fd6edce30d7ab345a9989de00bbd46ef284 # 0.34.0
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 0.35.0
with:
image-ref: ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build-and-push.outputs.digest }}
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
version: 'v0.70.0'
continue-on-error: true
- name: Check Trivy SARIF exists
@@ -558,15 +568,16 @@ jobs:
- name: Upload Trivy results
if: env.TRIGGER_EVENT != 'pull_request' && steps.skip.outputs.skip_build != 'true' && steps.trivy-check.outputs.exists == 'true'
uses: github/codeql-action/upload-sarif@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
with:
sarif_file: 'trivy-results.sarif'
category: '.github/workflows/docker-build.yml:build-and-push'
token: ${{ secrets.GITHUB_TOKEN }}
# Generate SBOM (Software Bill of Materials) for supply chain security
# Only for production builds (main/development) - feature branches use downstream supply-chain-pr.yml
- name: Generate SBOM
uses: anchore/sbom-action@28d71544de8eaf1b958d335707167c5f783590ad # v0.22.2
uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
if: env.TRIGGER_EVENT != 'pull_request' && steps.skip.outputs.skip_build != 'true' && steps.skip.outputs.is_feature_push != 'true'
with:
image: ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build-and-push.outputs.digest }}
@@ -575,7 +586,7 @@ jobs:
# Create verifiable attestation for the SBOM
- name: Attest SBOM
uses: actions/attest-sbom@4651f806c01d8637787e274ac3bdf724ef169f34 # v3.0.0
uses: actions/attest-sbom@c604332985a26aa8cf1bdc465b92731239ec6b9e # v4.1.0
if: env.TRIGGER_EVENT != 'pull_request' && steps.skip.outputs.skip_build != 'true' && steps.skip.outputs.is_feature_push != 'true'
with:
subject-name: ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}
@@ -586,7 +597,7 @@ jobs:
# Install Cosign for keyless signing
- name: Install Cosign
if: env.TRIGGER_EVENT != 'pull_request' && steps.skip.outputs.skip_build != 'true' && steps.skip.outputs.is_feature_push != 'true'
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
uses: sigstore/cosign-installer@cad07c2e89fa2edd6e2d7bab4c1aa38e53f76003 # v4.1.1
# Sign GHCR image with keyless signing (Sigstore/Fulcio)
- name: Sign GHCR Image
@@ -652,7 +663,7 @@ jobs:
echo "image_ref=${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:${PR_TAG}" >> "$GITHUB_OUTPUT"
- name: Log in to GitHub Container Registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ${{ env.GHCR_REGISTRY }}
username: ${{ github.actor }}
@@ -684,31 +695,67 @@ jobs:
echo "✅ Image freshness validated"
- name: Run Trivy scan on PR image (table output)
uses: aquasecurity/trivy-action@c1824fd6edce30d7ab345a9989de00bbd46ef284 # 0.34.0
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 0.35.0
with:
image-ref: ${{ steps.pr-image.outputs.image_ref }}
format: 'table'
severity: 'CRITICAL,HIGH'
exit-code: '0'
version: 'v0.70.0'
- name: Run Trivy scan on PR image (SARIF - blocking)
id: trivy-scan
uses: aquasecurity/trivy-action@c1824fd6edce30d7ab345a9989de00bbd46ef284 # 0.34.0
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 0.35.0
with:
image-ref: ${{ steps.pr-image.outputs.image_ref }}
format: 'sarif'
output: 'trivy-pr-results.sarif'
severity: 'CRITICAL,HIGH'
exit-code: '1' # Intended to block, but continued on error for now
version: 'v0.70.0'
continue-on-error: true
- name: Upload Trivy scan results
- name: Check Trivy PR SARIF exists
if: always()
uses: github/codeql-action/upload-sarif@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3
id: trivy-pr-check
run: |
if [ -f trivy-pr-results.sarif ]; then
echo "exists=true" >> "$GITHUB_OUTPUT"
else
echo "exists=false" >> "$GITHUB_OUTPUT"
fi
- name: Upload Trivy scan results
if: always() && steps.trivy-pr-check.outputs.exists == 'true'
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
with:
sarif_file: 'trivy-pr-results.sarif'
category: 'docker-pr-image'
- name: Upload Trivy compatibility results (docker-build category)
if: always() && steps.trivy-pr-check.outputs.exists == 'true'
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
with:
sarif_file: 'trivy-pr-results.sarif'
category: '.github/workflows/docker-build.yml:build-and-push'
continue-on-error: true
- name: Upload Trivy compatibility results (docker-publish alias)
if: always() && steps.trivy-pr-check.outputs.exists == 'true'
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
with:
sarif_file: 'trivy-pr-results.sarif'
category: '.github/workflows/docker-publish.yml:build-and-push'
continue-on-error: true
- name: Upload Trivy compatibility results (nightly alias)
if: always() && steps.trivy-pr-check.outputs.exists == 'true'
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
with:
sarif_file: 'trivy-pr-results.sarif'
category: 'trivy-nightly'
continue-on-error: true
- name: Create scan summary
if: always()
run: |

View File

@@ -44,7 +44,7 @@ jobs:
ref: ${{ github.event.workflow_run.head_sha || github.sha }}
- name: Set up Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: ${{ env.NODE_VERSION }}
@@ -53,7 +53,7 @@ jobs:
- name: Detect changed files
id: changes
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
env:
COMMIT_SHA: ${{ github.event.workflow_run.head_sha || github.sha }}
with:
@@ -95,7 +95,7 @@ jobs:
- name: Process issue files
id: process
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
env:
DRY_RUN: ${{ github.event.inputs.dry_run || 'false' }}
with:

View File

@@ -38,7 +38,7 @@ jobs:
# Step 2: Set up Node.js (for building any JS-based doc tools)
- name: 🔧 Set up Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: ${{ env.NODE_VERSION }}
@@ -352,7 +352,7 @@ jobs:
# Step 4: Upload the built site
- name: 📤 Upload artifact
uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5
with:
path: '_site'
@@ -372,7 +372,7 @@ jobs:
# Deploy to GitHub Pages
- name: 🚀 Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5
# Create a summary
- name: 📋 Create deployment summary

View File

@@ -80,11 +80,10 @@ on:
default: false
type: boolean
pull_request:
push:
env:
NODE_VERSION: '20'
GO_VERSION: '1.26.0'
GO_VERSION: '1.26.2'
GOTOOLCHAIN: auto
DOCKERHUB_REGISTRY: docker.io
IMAGE_NAME: ${{ github.repository_owner }}/charon
@@ -96,7 +95,7 @@ env:
CI_LOG_LEVEL: 'verbose'
concurrency:
group: e2e-split-${{ github.workflow }}-${{ github.ref }}-${{ github.event.pull_request.head.sha || github.sha }}
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
@@ -143,22 +142,23 @@ jobs:
- name: Set up Go
if: steps.resolve-image.outputs.image_source == 'build'
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version: ${{ env.GO_VERSION }}
cache: true
cache-dependency-path: backend/go.sum
- name: Set up Node.js
if: steps.resolve-image.outputs.image_source == 'build'
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Cache npm dependencies
if: steps.resolve-image.outputs.image_source == 'build'
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: ~/.npm
key: npm-${{ hashFiles('package-lock.json') }}
@@ -170,12 +170,12 @@ jobs:
- name: Set up Docker Buildx
if: steps.resolve-image.outputs.image_source == 'build'
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
- name: Build Docker image
id: build-image
if: steps.resolve-image.outputs.image_source == 'build'
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7
with:
context: .
file: ./Dockerfile
@@ -191,7 +191,7 @@ jobs:
- name: Upload Docker image artifact
if: steps.resolve-image.outputs.image_source == 'build'
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: docker-image
path: charon-e2e-image.tar
@@ -225,14 +225,15 @@ jobs:
ref: ${{ github.sha }}
- name: Set up Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Log in to Docker Hub
if: needs.build.outputs.image_source == 'registry'
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ${{ env.DOCKERHUB_REGISTRY }}
username: ${{ secrets.DOCKERHUB_USERNAME }}
@@ -247,7 +248,7 @@ jobs:
- name: Download Docker image artifact
if: needs.build.outputs.image_source == 'build'
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: docker-image
@@ -347,7 +348,7 @@ jobs:
- name: Upload HTML report (Chromium Security)
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: playwright-report-chromium-security
path: playwright-report/
@@ -355,7 +356,7 @@ jobs:
- name: Upload Chromium Security coverage (if enabled)
if: always() && (inputs.playwright_coverage == 'true' || vars.PLAYWRIGHT_COVERAGE == '1')
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: e2e-coverage-chromium-security
path: coverage/e2e/
@@ -363,7 +364,7 @@ jobs:
- name: Upload test traces on failure
if: failure()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: traces-chromium-security
path: test-results/**/*.zip
@@ -382,7 +383,7 @@ jobs:
- name: Upload diagnostics
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: e2e-diagnostics-chromium-security
path: diagnostics/
@@ -395,7 +396,7 @@ jobs:
- name: Upload Docker logs on failure
if: failure()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: docker-logs-chromium-security
path: docker-logs-chromium-security.txt
@@ -426,14 +427,15 @@ jobs:
ref: ${{ github.sha }}
- name: Set up Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Log in to Docker Hub
if: needs.build.outputs.image_source == 'registry'
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ${{ env.DOCKERHUB_REGISTRY }}
username: ${{ secrets.DOCKERHUB_USERNAME }}
@@ -448,7 +450,7 @@ jobs:
- name: Download Docker image artifact
if: needs.build.outputs.image_source == 'build'
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: docker-image
@@ -556,7 +558,7 @@ jobs:
- name: Upload HTML report (Firefox Security)
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: playwright-report-firefox-security
path: playwright-report/
@@ -564,7 +566,7 @@ jobs:
- name: Upload Firefox Security coverage (if enabled)
if: always() && (inputs.playwright_coverage == 'true' || vars.PLAYWRIGHT_COVERAGE == '1')
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: e2e-coverage-firefox-security
path: coverage/e2e/
@@ -572,7 +574,7 @@ jobs:
- name: Upload test traces on failure
if: failure()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: traces-firefox-security
path: test-results/**/*.zip
@@ -591,7 +593,7 @@ jobs:
- name: Upload diagnostics
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: e2e-diagnostics-firefox-security
path: diagnostics/
@@ -604,7 +606,7 @@ jobs:
- name: Upload Docker logs on failure
if: failure()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: docker-logs-firefox-security
path: docker-logs-firefox-security.txt
@@ -635,14 +637,15 @@ jobs:
ref: ${{ github.sha }}
- name: Set up Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Log in to Docker Hub
if: needs.build.outputs.image_source == 'registry'
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ${{ env.DOCKERHUB_REGISTRY }}
username: ${{ secrets.DOCKERHUB_USERNAME }}
@@ -657,7 +660,7 @@ jobs:
- name: Download Docker image artifact
if: needs.build.outputs.image_source == 'build'
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: docker-image
@@ -765,7 +768,7 @@ jobs:
- name: Upload HTML report (WebKit Security)
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: playwright-report-webkit-security
path: playwright-report/
@@ -773,7 +776,7 @@ jobs:
- name: Upload WebKit Security coverage (if enabled)
if: always() && (inputs.playwright_coverage == 'true' || vars.PLAYWRIGHT_COVERAGE == '1')
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: e2e-coverage-webkit-security
path: coverage/e2e/
@@ -781,7 +784,7 @@ jobs:
- name: Upload test traces on failure
if: failure()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: traces-webkit-security
path: test-results/**/*.zip
@@ -800,7 +803,7 @@ jobs:
- name: Upload diagnostics
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: e2e-diagnostics-webkit-security
path: diagnostics/
@@ -813,7 +816,7 @@ jobs:
- name: Upload Docker logs on failure
if: failure()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: docker-logs-webkit-security
path: docker-logs-webkit-security.txt
@@ -856,14 +859,47 @@ jobs:
ref: ${{ github.sha }}
- name: Set up Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Preflight disk diagnostics (before cleanup)
run: |
echo "Disk usage before cleanup"
df -h
docker system df || true
- name: Preflight cleanup (best effort)
run: |
echo "Best-effort cleanup for CI runner"
docker system prune -af || true
rm -rf playwright-report playwright-output coverage/e2e test-results diagnostics || true
rm -f docker-logs-*.txt charon-e2e-image.tar || true
- name: Preflight disk diagnostics and threshold gate
run: |
set -euo pipefail
MIN_FREE_BYTES=$((5 * 1024 * 1024 * 1024))
echo "Disk usage after cleanup"
df -h
docker system df || true
WORKSPACE_PATH="${GITHUB_WORKSPACE:-$PWD}"
FREE_ROOT_BYTES=$(df -PB1 / | awk 'NR==2 {print $4}')
FREE_WORKSPACE_BYTES=$(df -PB1 "$WORKSPACE_PATH" | awk 'NR==2 {print $4}')
echo "Free bytes on /: $FREE_ROOT_BYTES"
echo "Free bytes on workspace ($WORKSPACE_PATH): $FREE_WORKSPACE_BYTES"
if [ "$FREE_ROOT_BYTES" -lt "$MIN_FREE_BYTES" ] || [ "$FREE_WORKSPACE_BYTES" -lt "$MIN_FREE_BYTES" ]; then
echo "::error::[CI_DISK_PRESSURE] Insufficient free disk after cleanup. Required >= 5GiB on both / and workspace. root=${FREE_ROOT_BYTES}B workspace=${FREE_WORKSPACE_BYTES}B"
exit 42
fi
- name: Log in to Docker Hub
if: needs.build.outputs.image_source == 'registry'
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ${{ env.DOCKERHUB_REGISTRY }}
username: ${{ secrets.DOCKERHUB_USERNAME }}
@@ -878,7 +914,7 @@ jobs:
- name: Download Docker image artifact
if: needs.build.outputs.image_source == 'build'
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: docker-image
@@ -944,6 +980,7 @@ jobs:
--project=chromium \
--shard=${{ matrix.shard }}/${{ matrix.total-shards }} \
--output=playwright-output/chromium-shard-${{ matrix.shard }} \
tests/a11y \
tests/core \
tests/dns-provider-crud.spec.ts \
tests/dns-provider-types.spec.ts \
@@ -968,7 +1005,7 @@ jobs:
- name: Upload HTML report (Chromium shard ${{ matrix.shard }})
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: playwright-report-chromium-shard-${{ matrix.shard }}
path: playwright-report/
@@ -976,7 +1013,7 @@ jobs:
- name: Upload Playwright output (Chromium shard ${{ matrix.shard }})
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: playwright-output-chromium-shard-${{ matrix.shard }}
path: playwright-output/chromium-shard-${{ matrix.shard }}/
@@ -984,7 +1021,7 @@ jobs:
- name: Upload Chromium coverage (if enabled)
if: always() && (inputs.playwright_coverage == 'true' || vars.PLAYWRIGHT_COVERAGE == '1')
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: e2e-coverage-chromium-shard-${{ matrix.shard }}
path: coverage/e2e/
@@ -992,7 +1029,7 @@ jobs:
- name: Upload test traces on failure
if: failure()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: traces-chromium-shard-${{ matrix.shard }}
path: test-results/**/*.zip
@@ -1011,7 +1048,7 @@ jobs:
- name: Upload diagnostics
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: e2e-diagnostics-chromium-shard-${{ matrix.shard }}
path: diagnostics/
@@ -1024,7 +1061,7 @@ jobs:
- name: Upload Docker logs on failure
if: failure()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: docker-logs-chromium-shard-${{ matrix.shard }}
path: docker-logs-chromium-shard-${{ matrix.shard }}.txt
@@ -1060,14 +1097,47 @@ jobs:
ref: ${{ github.sha }}
- name: Set up Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Preflight disk diagnostics (before cleanup)
run: |
echo "Disk usage before cleanup"
df -h
docker system df || true
- name: Preflight cleanup (best effort)
run: |
echo "Best-effort cleanup for CI runner"
docker system prune -af || true
rm -rf playwright-report playwright-output coverage/e2e test-results diagnostics || true
rm -f docker-logs-*.txt charon-e2e-image.tar || true
- name: Preflight disk diagnostics and threshold gate
run: |
set -euo pipefail
MIN_FREE_BYTES=$((5 * 1024 * 1024 * 1024))
echo "Disk usage after cleanup"
df -h
docker system df || true
WORKSPACE_PATH="${GITHUB_WORKSPACE:-$PWD}"
FREE_ROOT_BYTES=$(df -PB1 / | awk 'NR==2 {print $4}')
FREE_WORKSPACE_BYTES=$(df -PB1 "$WORKSPACE_PATH" | awk 'NR==2 {print $4}')
echo "Free bytes on /: $FREE_ROOT_BYTES"
echo "Free bytes on workspace ($WORKSPACE_PATH): $FREE_WORKSPACE_BYTES"
if [ "$FREE_ROOT_BYTES" -lt "$MIN_FREE_BYTES" ] || [ "$FREE_WORKSPACE_BYTES" -lt "$MIN_FREE_BYTES" ]; then
echo "::error::[CI_DISK_PRESSURE] Insufficient free disk after cleanup. Required >= 5GiB on both / and workspace. root=${FREE_ROOT_BYTES}B workspace=${FREE_WORKSPACE_BYTES}B"
exit 42
fi
- name: Log in to Docker Hub
if: needs.build.outputs.image_source == 'registry'
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ${{ env.DOCKERHUB_REGISTRY }}
username: ${{ secrets.DOCKERHUB_USERNAME }}
@@ -1082,7 +1152,7 @@ jobs:
- name: Download Docker image artifact
if: needs.build.outputs.image_source == 'build'
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: docker-image
@@ -1156,6 +1226,7 @@ jobs:
--project=firefox \
--shard=${{ matrix.shard }}/${{ matrix.total-shards }} \
--output=playwright-output/firefox-shard-${{ matrix.shard }} \
tests/a11y \
tests/core \
tests/dns-provider-crud.spec.ts \
tests/dns-provider-types.spec.ts \
@@ -1180,7 +1251,7 @@ jobs:
- name: Upload HTML report (Firefox shard ${{ matrix.shard }})
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: playwright-report-firefox-shard-${{ matrix.shard }}
path: playwright-report/
@@ -1188,7 +1259,7 @@ jobs:
- name: Upload Playwright output (Firefox shard ${{ matrix.shard }})
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: playwright-output-firefox-shard-${{ matrix.shard }}
path: playwright-output/firefox-shard-${{ matrix.shard }}/
@@ -1196,7 +1267,7 @@ jobs:
- name: Upload Firefox coverage (if enabled)
if: always() && (inputs.playwright_coverage == 'true' || vars.PLAYWRIGHT_COVERAGE == '1')
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: e2e-coverage-firefox-shard-${{ matrix.shard }}
path: coverage/e2e/
@@ -1204,7 +1275,7 @@ jobs:
- name: Upload test traces on failure
if: failure()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: traces-firefox-shard-${{ matrix.shard }}
path: test-results/**/*.zip
@@ -1223,7 +1294,7 @@ jobs:
- name: Upload diagnostics
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: e2e-diagnostics-firefox-shard-${{ matrix.shard }}
path: diagnostics/
@@ -1236,7 +1307,7 @@ jobs:
- name: Upload Docker logs on failure
if: failure()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: docker-logs-firefox-shard-${{ matrix.shard }}
path: docker-logs-firefox-shard-${{ matrix.shard }}.txt
@@ -1272,14 +1343,47 @@ jobs:
ref: ${{ github.sha }}
- name: Set up Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Preflight disk diagnostics (before cleanup)
run: |
echo "Disk usage before cleanup"
df -h
docker system df || true
- name: Preflight cleanup (best effort)
run: |
echo "Best-effort cleanup for CI runner"
docker system prune -af || true
rm -rf playwright-report playwright-output coverage/e2e test-results diagnostics || true
rm -f docker-logs-*.txt charon-e2e-image.tar || true
- name: Preflight disk diagnostics and threshold gate
run: |
set -euo pipefail
MIN_FREE_BYTES=$((5 * 1024 * 1024 * 1024))
echo "Disk usage after cleanup"
df -h
docker system df || true
WORKSPACE_PATH="${GITHUB_WORKSPACE:-$PWD}"
FREE_ROOT_BYTES=$(df -PB1 / | awk 'NR==2 {print $4}')
FREE_WORKSPACE_BYTES=$(df -PB1 "$WORKSPACE_PATH" | awk 'NR==2 {print $4}')
echo "Free bytes on /: $FREE_ROOT_BYTES"
echo "Free bytes on workspace ($WORKSPACE_PATH): $FREE_WORKSPACE_BYTES"
if [ "$FREE_ROOT_BYTES" -lt "$MIN_FREE_BYTES" ] || [ "$FREE_WORKSPACE_BYTES" -lt "$MIN_FREE_BYTES" ]; then
echo "::error::[CI_DISK_PRESSURE] Insufficient free disk after cleanup. Required >= 5GiB on both / and workspace. root=${FREE_ROOT_BYTES}B workspace=${FREE_WORKSPACE_BYTES}B"
exit 42
fi
- name: Log in to Docker Hub
if: needs.build.outputs.image_source == 'registry'
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ${{ env.DOCKERHUB_REGISTRY }}
username: ${{ secrets.DOCKERHUB_USERNAME }}
@@ -1294,7 +1398,7 @@ jobs:
- name: Download Docker image artifact
if: needs.build.outputs.image_source == 'build'
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: docker-image
@@ -1368,6 +1472,7 @@ jobs:
--project=webkit \
--shard=${{ matrix.shard }}/${{ matrix.total-shards }} \
--output=playwright-output/webkit-shard-${{ matrix.shard }} \
tests/a11y \
tests/core \
tests/dns-provider-crud.spec.ts \
tests/dns-provider-types.spec.ts \
@@ -1392,7 +1497,7 @@ jobs:
- name: Upload HTML report (WebKit shard ${{ matrix.shard }})
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: playwright-report-webkit-shard-${{ matrix.shard }}
path: playwright-report/
@@ -1400,7 +1505,7 @@ jobs:
- name: Upload Playwright output (WebKit shard ${{ matrix.shard }})
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: playwright-output-webkit-shard-${{ matrix.shard }}
path: playwright-output/webkit-shard-${{ matrix.shard }}/
@@ -1408,7 +1513,7 @@ jobs:
- name: Upload WebKit coverage (if enabled)
if: always() && (inputs.playwright_coverage == 'true' || vars.PLAYWRIGHT_COVERAGE == '1')
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: e2e-coverage-webkit-shard-${{ matrix.shard }}
path: coverage/e2e/
@@ -1416,7 +1521,7 @@ jobs:
- name: Upload test traces on failure
if: failure()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: traces-webkit-shard-${{ matrix.shard }}
path: test-results/**/*.zip
@@ -1435,7 +1540,7 @@ jobs:
- name: Upload diagnostics
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: e2e-diagnostics-webkit-shard-${{ matrix.shard }}
path: diagnostics/
@@ -1448,7 +1553,7 @@ jobs:
- name: Upload Docker logs on failure
if: failure()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: docker-logs-webkit-shard-${{ matrix.shard }}
path: docker-logs-webkit-shard-${{ matrix.shard }}.txt
@@ -1504,7 +1609,7 @@ jobs:
steps:
- name: Check test results
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
env:
EFFECTIVE_BROWSER: ${{ inputs.browser || 'all' }}
EFFECTIVE_CATEGORY: ${{ inputs.test_category || 'all' }}

File diff suppressed because it is too large Load Diff

View File

@@ -1,632 +0,0 @@
# E2E Tests Workflow
# Runs Playwright E2E tests with sharding for faster execution
# and collects frontend code coverage via @bgotink/playwright-coverage
#
# Test Execution Architecture:
# - Parallel Sharding: Tests split across 4 shards for speed
# - Per-Shard HTML Reports: Each shard generates its own HTML report
# - No Merging Needed: Smaller reports are easier to debug
# - Trace Collection: Failure traces captured for debugging
#
# Coverage Architecture:
# - Backend: Docker container at localhost:8080 (API)
# - Frontend: Vite dev server at localhost:3000 (serves source files)
# - Tests hit Vite, which proxies API calls to Docker
# - V8 coverage maps directly to source files for accurate reporting
# - Coverage disabled by default (requires PLAYWRIGHT_COVERAGE=1)
#
# Triggers:
# - Pull requests to main/develop (with path filters)
# - Push to main branch
# - Manual dispatch with browser selection
#
# Jobs:
# 1. build: Build Docker image and upload as artifact
# 2. e2e-tests: Run tests in parallel shards, upload per-shard HTML reports
# 3. test-summary: Generate summary with links to shard reports
# 4. comment-results: Post test results as PR comment
# 5. upload-coverage: Merge and upload E2E coverage to Codecov (if enabled)
# 6. e2e-results: Status check to block merge on failure
name: E2E Tests
on:
pull_request:
branches:
- main
- development
- 'feature/**'
paths:
- 'frontend/**'
- 'backend/**'
- 'tests/**'
- 'playwright.config.js'
- '.github/workflows/e2e-tests.yml'
workflow_dispatch:
inputs:
browser:
description: 'Browser to test'
required: false
default: 'chromium'
type: choice
options:
- chromium
- firefox
- webkit
- all
env:
NODE_VERSION: '20'
GO_VERSION: '1.25.6'
GOTOOLCHAIN: auto
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository_owner }}/charon
PLAYWRIGHT_COVERAGE: ${{ vars.PLAYWRIGHT_COVERAGE || '0' }}
# Enhanced debugging environment variables
DEBUG: 'charon:*,charon-test:*'
PLAYWRIGHT_DEBUG: '1'
CI_LOG_LEVEL: 'verbose'
concurrency:
group: e2e-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
# Build application once, share across test shards
build:
name: Build Application
runs-on: ubuntu-latest
outputs:
image_digest: ${{ steps.build-image.outputs.digest }}
steps:
- name: Checkout repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- name: Set up Go
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
with:
go-version: ${{ env.GO_VERSION }}
cache: true
cache-dependency-path: backend/go.sum
- name: Set up Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Cache npm dependencies
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5
with:
path: ~/.npm
key: npm-${{ hashFiles('package-lock.json') }}
restore-keys: npm-
- name: Install dependencies
run: npm ci
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Build Docker image
id: build-image
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
with:
context: .
file: ./Dockerfile
push: false
load: true
tags: charon:e2e-test
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Save Docker image
run: docker save charon:e2e-test -o charon-e2e-image.tar
- name: Upload Docker image artifact
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: docker-image
path: charon-e2e-image.tar
retention-days: 1
# Run tests in parallel shards
e2e-tests:
name: E2E ${{ matrix.browser }} (Shard ${{ matrix.shard }}/${{ matrix.total-shards }})
runs-on: ubuntu-latest
needs: build
timeout-minutes: 30
env:
# Required for security teardown (emergency reset fallback when ACL blocks API)
CHARON_EMERGENCY_TOKEN: ${{ secrets.CHARON_EMERGENCY_TOKEN }}
# Enable security-focused endpoints and test gating
CHARON_EMERGENCY_SERVER_ENABLED: "true"
CHARON_SECURITY_TESTS_ENABLED: "true"
CHARON_E2E_IMAGE_TAG: charon:e2e-test
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4]
total-shards: [4]
browser: [chromium, firefox, webkit]
steps:
- name: Checkout repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- name: Set up Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Download Docker image
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
with:
name: docker-image
- name: Validate Emergency Token Configuration
run: |
echo "🔐 Validating emergency token configuration..."
if [ -z "$CHARON_EMERGENCY_TOKEN" ]; then
echo "::error title=Missing Secret::CHARON_EMERGENCY_TOKEN secret not configured in repository settings"
echo "::error::Navigate to: Repository Settings → Secrets and Variables → Actions"
echo "::error::Create secret: CHARON_EMERGENCY_TOKEN"
echo "::error::Generate value with: openssl rand -hex 32"
echo "::error::See docs/github-setup.md for detailed instructions"
exit 1
fi
TOKEN_LENGTH=${#CHARON_EMERGENCY_TOKEN}
if [ $TOKEN_LENGTH -lt 64 ]; then
echo "::error title=Invalid Token Length::CHARON_EMERGENCY_TOKEN must be at least 64 characters (current: $TOKEN_LENGTH)"
echo "::error::Generate new token with: openssl rand -hex 32"
exit 1
fi
# Mask token in output (show first 8 chars only)
MASKED_TOKEN="${CHARON_EMERGENCY_TOKEN:0:8}...${CHARON_EMERGENCY_TOKEN: -4}"
echo "::notice::Emergency token validated (length: $TOKEN_LENGTH, preview: $MASKED_TOKEN)"
env:
CHARON_EMERGENCY_TOKEN: ${{ secrets.CHARON_EMERGENCY_TOKEN }}
- name: Load Docker image
run: |
docker load -i charon-e2e-image.tar
docker images | grep charon
- name: Generate ephemeral encryption key
run: |
# Generate a unique, ephemeral encryption key for this CI run
# Key is 32 bytes, base64-encoded as required by CHARON_ENCRYPTION_KEY
echo "CHARON_ENCRYPTION_KEY=$(openssl rand -base64 32)" >> $GITHUB_ENV
echo "✅ Generated ephemeral encryption key for E2E tests"
- name: Start test environment
run: |
# Use docker-compose.playwright-ci.yml for CI (no .env file, uses GitHub Secrets)
# Note: Using pre-built image loaded from artifact - no rebuild needed
docker compose -f .docker/compose/docker-compose.playwright-ci.yml --profile security-tests up -d
echo "✅ Container started via docker-compose.playwright-ci.yml"
- name: Wait for service health
run: |
echo "⏳ Waiting for Charon to be healthy..."
MAX_ATTEMPTS=30
ATTEMPT=0
while [[ ${ATTEMPT} -lt ${MAX_ATTEMPTS} ]]; do
ATTEMPT=$((ATTEMPT + 1))
echo "Attempt ${ATTEMPT}/${MAX_ATTEMPTS}..."
if curl -sf http://localhost:8080/api/v1/health > /dev/null 2>&1; then
echo "✅ Charon is healthy!"
curl -s http://localhost:8080/api/v1/health | jq .
exit 0
fi
sleep 2
done
echo "❌ Health check failed"
docker compose -f .docker/compose/docker-compose.playwright-ci.yml logs
exit 1
- name: Install dependencies
run: npm ci
- name: Clean Playwright browser cache
run: rm -rf ~/.cache/ms-playwright
- name: Cache Playwright browsers
id: playwright-cache
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5
with:
path: ~/.cache/ms-playwright
# Use exact match only - no restore-keys fallback
# This ensures we don't restore stale browsers when Playwright version changes
key: playwright-${{ matrix.browser }}-${{ hashFiles('package-lock.json') }}
- name: Install & verify Playwright browsers
run: |
npx playwright install --with-deps --force
set -euo pipefail
echo "🎯 Playwright CLI version"
npx playwright --version || true
echo "🔍 Showing Playwright cache root (if present)"
ls -la ~/.cache/ms-playwright || true
echo "📥 Install or verify browser: ${{ matrix.browser }}"
# Install when cache miss, otherwise verify the expected executables exist
if [[ "${{ steps.playwright-cache.outputs.cache-hit }}" != "true" ]]; then
echo "📥 Cache miss - downloading ${{ matrix.browser }} browser..."
npx playwright install --with-deps ${{ matrix.browser }}
else
echo "✅ Cache hit - verifying ${{ matrix.browser }} browser files..."
fi
# Look for the browser-specific headless shell executable(s)
case "${{ matrix.browser }}" in
chromium)
EXPECTED_PATTERN="chrome-headless-shell*"
;;
firefox)
EXPECTED_PATTERN="firefox*"
;;
webkit)
EXPECTED_PATTERN="webkit*"
;;
*)
EXPECTED_PATTERN="*"
;;
esac
echo "Searching for expected files (pattern=$EXPECTED_PATTERN)..."
find ~/.cache/ms-playwright -maxdepth 4 -type f -name "$EXPECTED_PATTERN" -print || true
# Attempt to derive the exact executable path Playwright will use
echo "Attempting to resolve Playwright's executable path via Node API (best-effort)"
node -e "try{ const pw = require('playwright'); const b = pw['${{ matrix.browser }}']; console.log('exePath:', b.executablePath ? b.executablePath() : 'n/a'); }catch(e){ console.error('node-check-failed', e.message); process.exit(0); }" || true
# If the expected binary is missing, force reinstall
MISSING_COUNT=$(find ~/.cache/ms-playwright -maxdepth 4 -type f -name "$EXPECTED_PATTERN" | wc -l || true)
if [[ "$MISSING_COUNT" -lt 1 ]]; then
echo "⚠️ Expected Playwright browser executable not found (count=$MISSING_COUNT). Forcing reinstall..."
npx playwright install --with-deps ${{ matrix.browser }} --force
fi
echo "Post-install: show cache contents (top 5 lines)"
find ~/.cache/ms-playwright -maxdepth 3 -printf '%p\n' | head -40 || true
# Final sanity check: try a headless launch via a tiny Node script (browser-specific args, retry without args)
echo "🔁 Verifying browser can be launched (headless)"
node -e "(async()=>{ try{ const pw=require('playwright'); const name='${{ matrix.browser }}'; const browser = pw[name]; const argsMap = { chromium: ['--no-sandbox'], firefox: ['--no-sandbox'], webkit: [] }; const args = argsMap[name] || [];
// First attempt: launch with recommended args for this browser
try {
console.log('attempt-launch', name, 'args', JSON.stringify(args));
const b = await browser.launch({ headless: true, args });
await b.close();
console.log('launch-ok', 'argsUsed', JSON.stringify(args));
process.exit(0);
} catch (err) {
console.warn('launch-with-args-failed', err && err.message);
if (args.length) {
// Retry without args (some browsers reject unknown flags)
console.log('retrying-without-args');
const b2 = await browser.launch({ headless: true });
await b2.close();
console.log('launch-ok-no-args');
process.exit(0);
}
throw err;
}
} catch (e) { console.error('launch-failed', e && e.message); process.exit(2); } })()" || (echo '❌ Browser launch verification failed' && exit 1)
echo "✅ Playwright ${{ matrix.browser }} ready and verified"
- name: Run E2E tests (Shard ${{ matrix.shard }}/${{ matrix.total-shards }})
run: |
echo "════════════════════════════════════════════════════════════"
echo "E2E Test Shard ${{ matrix.shard }}/${{ matrix.total-shards }}"
echo "Browser: ${{ matrix.browser }}"
echo "Start Time: $(date -u +'%Y-%m-%dT%H:%M:%SZ')"
echo ""
echo "Reporter: HTML (per-shard reports)"
echo "Output: playwright-report/ directory"
echo "════════════════════════════════════════════════════════════"
# Capture start time for performance budget tracking
SHARD_START=$(date +%s)
echo "SHARD_START=$SHARD_START" >> $GITHUB_ENV
npx playwright test \
--project=${{ matrix.browser }} \
--shard=${{ matrix.shard }}/${{ matrix.total-shards }}
# Capture end time for performance budget tracking
SHARD_END=$(date +%s)
echo "SHARD_END=$SHARD_END" >> $GITHUB_ENV
SHARD_DURATION=$((SHARD_END - SHARD_START))
echo ""
echo "════════════════════════════════════════════════════════════"
echo "Shard ${{ matrix.shard }} Complete | Duration: ${SHARD_DURATION}s"
echo "════════════════════════════════════════════════════════════"
env:
# Test directly against Docker container (no coverage)
PLAYWRIGHT_BASE_URL: http://localhost:8080
CI: true
TEST_WORKER_INDEX: ${{ matrix.shard }}
- name: Verify shard performance budget
if: always()
run: |
# Calculate shard execution time
SHARD_DURATION=$((SHARD_END - SHARD_START))
MAX_DURATION=900 # 15 minutes
echo "📊 Performance Budget Check"
echo " Shard Duration: ${SHARD_DURATION}s"
echo " Budget Limit: ${MAX_DURATION}s"
echo " Utilization: $((SHARD_DURATION * 100 / MAX_DURATION))%"
# Fail if shard exceeded performance budget
if [[ $SHARD_DURATION -gt $MAX_DURATION ]]; then
echo "::error::Shard exceeded performance budget: ${SHARD_DURATION}s > ${MAX_DURATION}s"
echo "::error::This likely indicates feature flag polling regression or API bottleneck"
echo "::error::Review test logs and consider optimizing wait helpers or API calls"
exit 1
fi
echo "✅ Shard completed within budget: ${SHARD_DURATION}s"
- name: Upload HTML report (per-shard)
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: playwright-report-${{ matrix.browser }}-shard-${{ matrix.shard }}
path: playwright-report/
retention-days: 14
- name: Upload test traces on failure
if: failure()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: traces-${{ matrix.browser }}-shard-${{ matrix.shard }}
path: test-results/**/*.zip
retention-days: 7
- name: Collect Docker logs on failure
if: failure()
run: |
echo "📋 Container logs:"
docker compose -f .docker/compose/docker-compose.playwright-ci.yml logs > docker-logs-${{ matrix.browser }}-shard-${{ matrix.shard }}.txt 2>&1
- name: Upload Docker logs on failure
if: failure()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: docker-logs-${{ matrix.browser }}-shard-${{ matrix.shard }}
path: docker-logs-${{ matrix.browser }}-shard-${{ matrix.shard }}.txt
retention-days: 7
- name: Cleanup
if: always()
run: |
docker compose -f .docker/compose/docker-compose.playwright-ci.yml down -v 2>/dev/null || true
# Summarize test results from all shards (no merging needed)
test-summary:
name: E2E Test Summary
runs-on: ubuntu-latest
needs: e2e-tests
if: always()
steps:
- name: Generate job summary with per-shard links
run: |
echo "## 📊 E2E Test Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Per-Shard HTML Reports" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Each shard generates its own HTML report for easier debugging:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Browser | Shards | HTML Reports | Traces (on failure) |" >> $GITHUB_STEP_SUMMARY
echo "|---------|--------|--------------|---------------------|" >> $GITHUB_STEP_SUMMARY
echo "| Chromium | 1-4 | \`playwright-report-chromium-shard-{1..4}\` | \`traces-chromium-shard-{1..4}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Firefox | 1-4 | \`playwright-report-firefox-shard-{1..4}\` | \`traces-firefox-shard-{1..4}\` |" >> $GITHUB_STEP_SUMMARY
echo "| WebKit | 1-4 | \`playwright-report-webkit-shard-{1..4}\` | \`traces-webkit-shard-{1..4}\` |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### How to View Reports" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "1. Download the shard HTML report artifact (zip file)" >> $GITHUB_STEP_SUMMARY
echo "2. Extract and open \`index.html\` in your browser" >> $GITHUB_STEP_SUMMARY
echo "3. Or run: \`npx playwright show-report path/to/extracted-folder\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Debugging Tips" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Failed tests?** Download the shard report that failed. Each shard has a focused subset of tests." >> $GITHUB_STEP_SUMMARY
echo "- **Traces**: Available in trace artifacts (only on failure)" >> $GITHUB_STEP_SUMMARY
echo "- **Docker Logs**: Backend errors available in docker-logs-shard-N artifacts" >> $GITHUB_STEP_SUMMARY
echo "- **Local repro**: \`npx playwright test --grep=\"test name\"\`" >> $GITHUB_STEP_SUMMARY
# Comment on PR with results
comment-results:
name: Comment Test Results
runs-on: ubuntu-latest
needs: [e2e-tests, test-summary]
if: github.event_name == 'pull_request' && always()
permissions:
pull-requests: write
steps:
- name: Determine test status
id: status
run: |
if [[ "${{ needs.e2e-tests.result }}" == "success" ]]; then
echo "emoji=✅" >> $GITHUB_OUTPUT
echo "status=PASSED" >> $GITHUB_OUTPUT
echo "message=All E2E tests passed!" >> $GITHUB_OUTPUT
elif [[ "${{ needs.e2e-tests.result }}" == "failure" ]]; then
echo "emoji=❌" >> $GITHUB_OUTPUT
echo "status=FAILED" >> $GITHUB_OUTPUT
echo "message=Some E2E tests failed. Check artifacts for per-shard reports." >> $GITHUB_OUTPUT
else
echo "emoji=⚠️" >> $GITHUB_OUTPUT
echo "status=UNKNOWN" >> $GITHUB_OUTPUT
echo "message=E2E tests did not complete successfully." >> $GITHUB_OUTPUT
fi
- name: Comment on PR
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
script: |
const emoji = '${{ steps.status.outputs.emoji }}';
const status = '${{ steps.status.outputs.status }}';
const message = '${{ steps.status.outputs.message }}';
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
const body = `## ${emoji} E2E Test Results: ${status}
${message}
| Metric | Result |
|--------|--------|
| Browsers | Chromium, Firefox, WebKit |
| Shards per Browser | 4 |
| Total Jobs | 12 |
| Status | ${status} |
**Per-Shard HTML Reports** (easier to debug):
- \`playwright-report-{browser}-shard-{1..4}\` (12 total artifacts)
- Trace artifacts: \`traces-{browser}-shard-{N}\`
[📊 View workflow run & download reports](${runUrl})
---
<sub>🤖 This comment was automatically generated by the E2E Tests workflow.</sub>`;
// Find existing comment
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const botComment = comments.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('E2E Test Results')
);
if (botComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: body
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: body
});
}
# Upload merged E2E coverage to Codecov
upload-coverage:
name: Upload E2E Coverage
runs-on: ubuntu-latest
needs: e2e-tests
# Coverage is only produced when PLAYWRIGHT_COVERAGE=1 (requires Vite dev server)
if: vars.PLAYWRIGHT_COVERAGE == '1'
steps:
- name: Checkout repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- name: Set up Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Download all coverage artifacts
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
with:
pattern: e2e-coverage-*
path: all-coverage
merge-multiple: false
- name: Merge LCOV coverage files
run: |
# Install lcov for merging
sudo apt-get update && sudo apt-get install -y lcov
# Create merged coverage directory
mkdir -p coverage/e2e-merged
# Find all lcov.info files and merge them
LCOV_FILES=$(find all-coverage -name "lcov.info" -type f)
if [[ -n "$LCOV_FILES" ]]; then
# Build merge command
MERGE_ARGS=""
for file in $LCOV_FILES; do
MERGE_ARGS="$MERGE_ARGS -a $file"
done
lcov $MERGE_ARGS -o coverage/e2e-merged/lcov.info
echo "✅ Merged $(echo "$LCOV_FILES" | wc -w) coverage files"
else
echo "⚠️ No coverage files found to merge"
exit 0
fi
- name: Upload E2E coverage to Codecov
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage/e2e-merged/lcov.info
flags: e2e
name: e2e-coverage
fail_ci_if_error: false
- name: Upload merged coverage artifact
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: e2e-coverage-merged
path: coverage/e2e-merged/
retention-days: 30
# Final status check - blocks merge if tests fail
e2e-results:
name: E2E Test Results
runs-on: ubuntu-latest
needs: e2e-tests
if: always()
steps:
- name: Check test results
run: |
if [[ "${{ needs.e2e-tests.result }}" == "success" ]]; then
echo "✅ All E2E tests passed"
exit 0
elif [[ "${{ needs.e2e-tests.result }}" == "skipped" ]]; then
echo "⏭️ E2E tests were skipped"
exit 0
else
echo "❌ E2E tests failed or were cancelled"
echo "Result: ${{ needs.e2e-tests.result }}"
exit 1
fi

View File

@@ -7,6 +7,9 @@ on:
required: true
type: string
permissions:
contents: read
jobs:
cleanup:
runs-on: ubuntu-latest

View File

@@ -9,6 +9,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.workflow_run.head_branch || github.head_ref || github.ref_name }}
cancel-in-progress: true
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest

View File

@@ -15,13 +15,16 @@ on:
default: "false"
env:
GO_VERSION: '1.26.0'
GO_VERSION: '1.26.2'
NODE_VERSION: '24.12.0'
GOTOOLCHAIN: auto
GHCR_REGISTRY: ghcr.io
DOCKERHUB_REGISTRY: docker.io
IMAGE_NAME: wikid82/charon
permissions:
contents: read
jobs:
sync-development-to-nightly:
runs-on: ubuntu-latest
@@ -86,7 +89,7 @@ jobs:
contents: read
steps:
- name: Dispatch Missing Nightly Validation Workflows
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
const owner = context.repo.owner;
@@ -103,11 +106,12 @@ jobs:
const workflows = [
{ id: 'e2e-tests-split.yml' },
{ id: 'codecov-upload.yml', inputs: { run_backend: 'true', run_frontend: 'true' } },
{ id: 'security-pr.yml' },
{ id: 'supply-chain-verify.yml' },
{ id: 'codeql.yml' },
];
core.info('Skipping security-pr.yml: PR-only workflow intentionally excluded from nightly non-PR dispatch');
for (const workflow of workflows) {
const { data: workflowRuns } = await github.rest.actions.listWorkflowRuns({
owner,
@@ -147,27 +151,37 @@ jobs:
id-token: write
outputs:
version: ${{ steps.meta.outputs.version }}
tags: ${{ steps.meta.outputs.tags }}
digest: ${{ steps.build.outputs.digest }}
digest: ${{ steps.resolve_digest.outputs.digest }}
steps:
- name: Checkout nightly branch
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: nightly
ref: ${{ github.event_name == 'workflow_dispatch' && github.ref || 'nightly' }}
fetch-depth: 0
- name: Set lowercase image name
run: echo "IMAGE_NAME_LC=${IMAGE_NAME,,}" >> "$GITHUB_ENV"
- name: Set up QEMU
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Resolve Alpine base image digest
id: alpine
run: |
ALPINE_IMAGE_REF=$(grep -m1 'ARG ALPINE_IMAGE=' Dockerfile | cut -d'=' -f2-)
if [[ -z "$ALPINE_IMAGE_REF" ]]; then
echo "::error::Failed to parse ALPINE_IMAGE from Dockerfile"
exit 1
fi
echo "Resolved Alpine image: ${ALPINE_IMAGE_REF}"
echo "image=${ALPINE_IMAGE_REF}" >> "$GITHUB_OUTPUT"
- name: Log in to GitHub Container Registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ${{ env.GHCR_REGISTRY }}
username: ${{ github.actor }}
@@ -175,7 +189,7 @@ jobs:
- name: Log in to Docker Hub
if: env.HAS_DOCKERHUB_TOKEN == 'true'
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: docker.io
username: ${{ secrets.DOCKERHUB_USERNAME }}
@@ -183,7 +197,7 @@ jobs:
- name: Extract metadata
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
with:
images: |
${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}
@@ -198,7 +212,7 @@ jobs:
- name: Build and push Docker image
id: build
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
context: .
platforms: linux/amd64,linux/arm64
@@ -209,25 +223,112 @@ jobs:
VERSION=nightly-${{ github.sha }}
VCS_REF=${{ github.sha }}
BUILD_DATE=${{ github.event.repository.pushed_at }}
ALPINE_IMAGE=${{ steps.alpine.outputs.image }}
cache-from: type=gha
cache-to: type=gha,mode=max
provenance: true
sbom: true
- name: Resolve and export image digest
id: resolve_digest
run: |
set -euo pipefail
DIGEST="${{ steps.build.outputs.digest }}"
if [[ -z "$DIGEST" ]]; then
echo "Build action digest empty; querying GHCR registry API..."
GHCR_TOKEN=$(curl -sf \
-u "${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}" \
"https://ghcr.io/token?scope=repository:${{ env.IMAGE_NAME }}:pull&service=ghcr.io" \
| jq -r '.token')
DIGEST=$(curl -sfI \
-H "Authorization: Bearer ${GHCR_TOKEN}" \
-H "Accept: application/vnd.oci.image.index.v1+json,application/vnd.docker.distribution.manifest.list.v2+json,application/vnd.oci.image.manifest.v1+json" \
"https://ghcr.io/v2/${{ env.IMAGE_NAME }}/manifests/nightly" \
| grep -i '^docker-content-digest:' | awk '{print $2}' | tr -d '\r' || true)
[[ -n "$DIGEST" ]] && echo "Resolved from GHCR API: ${DIGEST}"
fi
if [[ -z "$DIGEST" ]]; then
echo "::error::Could not determine image digest from step output or GHCR registry API"
exit 1
fi
echo "RESOLVED_DIGEST=${DIGEST}" >> "$GITHUB_ENV"
echo "digest=${DIGEST}" >> "$GITHUB_OUTPUT"
echo "Exported digest: ${DIGEST}"
- name: Record nightly image digest
run: |
echo "## 🧾 Nightly Image Digest" >> "$GITHUB_STEP_SUMMARY"
echo "- ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:nightly@${{ steps.build.outputs.digest }}" >> "$GITHUB_STEP_SUMMARY"
echo "- ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:nightly@${{ steps.resolve_digest.outputs.digest }}" >> "$GITHUB_STEP_SUMMARY"
- name: Generate SBOM
uses: anchore/sbom-action@28d71544de8eaf1b958d335707167c5f783590ad # v0.22.2
id: sbom_primary
continue-on-error: true
uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
with:
image: ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:nightly@${{ steps.build.outputs.digest }}
image: ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.resolve_digest.outputs.digest }}
format: cyclonedx-json
output-file: sbom-nightly.json
syft-version: v1.42.1
- name: Generate SBOM fallback with pinned Syft
if: always()
run: |
set -euo pipefail
if [[ "${{ steps.sbom_primary.outcome }}" == "success" ]] && [[ -s sbom-nightly.json ]] && jq -e . sbom-nightly.json >/dev/null 2>&1; then
echo "Primary SBOM generation succeeded with valid JSON; skipping fallback"
exit 0
fi
echo "Primary SBOM generation failed or produced missing/invalid output; using deterministic Syft fallback"
SYFT_VERSION="v1.42.4"
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
ARCH="$(uname -m)"
case "$ARCH" in
x86_64) ARCH="amd64" ;;
aarch64|arm64) ARCH="arm64" ;;
*) echo "Unsupported architecture: $ARCH"; exit 1 ;;
esac
TARBALL="syft_${SYFT_VERSION#v}_${OS}_${ARCH}.tar.gz"
BASE_URL="https://github.com/anchore/syft/releases/download/${SYFT_VERSION}"
curl -fsSLo "$TARBALL" "${BASE_URL}/${TARBALL}"
curl -fsSLo checksums.txt "${BASE_URL}/syft_${SYFT_VERSION#v}_checksums.txt"
grep " ${TARBALL}$" checksums.txt > checksum_line.txt
sha256sum -c checksum_line.txt
tar -xzf "$TARBALL" syft
chmod +x syft
DIGEST="${{ steps.resolve_digest.outputs.digest }}"
if [[ -z "$DIGEST" ]]; then
echo "::error::Digest from resolve_digest step is empty; the digest-resolution step did not complete successfully"
exit 1
fi
./syft "${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}@${DIGEST}" -o cyclonedx-json=sbom-nightly.json
- name: Verify SBOM artifact
if: always()
run: |
set -euo pipefail
test -s sbom-nightly.json
jq -e . sbom-nightly.json >/dev/null
jq -e '
.bomFormat == "CycloneDX"
and (.specVersion | type == "string" and length > 0)
and has("version")
and has("metadata")
and (.components | type == "array")
' sbom-nightly.json >/dev/null
- name: Upload SBOM artifact
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: sbom-nightly
path: sbom-nightly.json
@@ -235,13 +336,13 @@ jobs:
# Install Cosign for keyless signing
- name: Install Cosign
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
uses: sigstore/cosign-installer@cad07c2e89fa2edd6e2d7bab4c1aa38e53f76003 # v4.1.1
# Sign GHCR image with keyless signing (Sigstore/Fulcio)
- name: Sign GHCR Image
run: |
echo "Signing GHCR nightly image with keyless signing..."
cosign sign --yes "${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}"
cosign sign --yes "${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.resolve_digest.outputs.digest }}"
echo "✅ GHCR nightly image signed successfully"
# Sign Docker Hub image with keyless signing (Sigstore/Fulcio)
@@ -249,7 +350,7 @@ jobs:
if: env.HAS_DOCKERHUB_TOKEN == 'true'
run: |
echo "Signing Docker Hub nightly image with keyless signing..."
cosign sign --yes "${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}"
cosign sign --yes "${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.resolve_digest.outputs.digest }}"
echo "✅ Docker Hub nightly image signed successfully"
# Attach SBOM to Docker Hub image
@@ -257,7 +358,7 @@ jobs:
if: env.HAS_DOCKERHUB_TOKEN == 'true'
run: |
echo "Attaching SBOM to Docker Hub nightly image..."
cosign attach sbom --sbom sbom-nightly.json "${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}"
cosign attach sbom --sbom sbom-nightly.json "${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.resolve_digest.outputs.digest }}"
echo "✅ SBOM attached to Docker Hub nightly image"
test-nightly-image:
@@ -271,13 +372,13 @@ jobs:
- name: Checkout nightly branch
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: nightly
ref: ${{ github.event_name == 'workflow_dispatch' && github.ref || 'nightly' }}
- name: Set lowercase image name
run: echo "IMAGE_NAME_LC=${IMAGE_NAME,,}" >> "$GITHUB_ENV"
- name: Log in to GitHub Container Registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ${{ env.GHCR_REGISTRY }}
username: ${{ github.actor }}
@@ -288,18 +389,33 @@ jobs:
- name: Run container smoke test
run: |
IMAGE_REF="${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:nightly@${{ needs.build-and-push-nightly.outputs.digest }}"
docker run --name charon-nightly -d \
-p 8080:8080 \
"${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:nightly@${{ needs.build-and-push-nightly.outputs.digest }}"
"${IMAGE_REF}"
# Wait for container to start
sleep 10
# Wait for container to become healthy
echo "⏳ Waiting for Charon to be healthy..."
MAX_ATTEMPTS=30
ATTEMPT=0
while [[ ${ATTEMPT} -lt ${MAX_ATTEMPTS} ]]; do
ATTEMPT=$((ATTEMPT + 1))
echo "Attempt ${ATTEMPT}/${MAX_ATTEMPTS}..."
if docker exec charon-nightly wget -qO- http://127.0.0.1:8080/health > /dev/null 2>&1; then
echo "✅ Charon is healthy!"
docker exec charon-nightly wget -qO- http://127.0.0.1:8080/health
break
fi
sleep 2
done
# Check container is running
docker ps | grep charon-nightly
# Basic health check
curl -f http://localhost:8080/health || exit 1
if [[ ${ATTEMPT} -ge ${MAX_ATTEMPTS} ]]; then
echo "❌ Health check failed after ${MAX_ATTEMPTS} attempts"
docker logs charon-nightly
docker stop charon-nightly
docker rm charon-nightly
exit 1
fi
# Cleanup
docker stop charon-nightly
@@ -325,40 +441,211 @@ jobs:
- name: Checkout nightly branch
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: nightly
ref: ${{ github.event_name == 'workflow_dispatch' && github.ref || 'nightly' }}
- name: Set lowercase image name
run: echo "IMAGE_NAME_LC=${IMAGE_NAME,,}" >> "$GITHUB_ENV"
- name: Download SBOM
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: sbom-nightly
- name: Scan with Grype
uses: anchore/scan-action@7037fa011853d5a11690026fb85feee79f4c946c # v7.3.2
uses: anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2 # v7.4.0
with:
sbom: sbom-nightly.json
fail-build: false
severity-cutoff: high
- name: Scan with Trivy
uses: aquasecurity/trivy-action@c1824fd6edce30d7ab345a9989de00bbd46ef284 # 0.34.0
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 0.35.0
with:
image-ref: ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build-and-push-nightly.outputs.digest }}
image-ref: ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:nightly@${{ needs.build-and-push-nightly.outputs.digest }}
format: 'sarif'
output: 'trivy-nightly.sarif'
version: 'v0.70.0'
trivyignores: '.trivyignore'
- name: Upload Trivy results
uses: github/codeql-action/upload-sarif@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
with:
sarif_file: 'trivy-nightly.sarif'
category: 'trivy-nightly'
- name: Check for critical CVEs
- name: Security severity policy summary
run: |
if grep -q "CRITICAL" trivy-nightly.sarif; then
echo "❌ Critical vulnerabilities found in nightly build"
{
echo "## 🔐 Nightly Supply Chain Severity Policy"
echo ""
echo "- Blocking: Critical, High"
echo "- Medium: non-blocking by default (report + triage SLA)"
echo "- Policy file: .github/security-severity-policy.yml"
} >> "$GITHUB_STEP_SUMMARY"
- name: Check for Critical/High CVEs
run: |
set -euo pipefail
jq -e . trivy-nightly.sarif >/dev/null
CRITICAL_COUNT=$(jq -r '
[
.runs[] as $run
| ($run.tool.driver.rules // []) as $rules
| $run.results[]?
| . as $result
| (
(
if (($result.ruleIndex | type) == "number") then
($rules[$result.ruleIndex].properties["security-severity"] // empty)
else
empty
end
)
// ([
$rules[]?
| select((.id // "") == ($result.ruleId // ""))
| .properties["security-severity"]
][0] // empty)
// empty
) as $securitySeverity
| (try ($securitySeverity | tonumber) catch empty) as $score
| select($score != null and $score >= 9.0)
] | length
' trivy-nightly.sarif)
HIGH_COUNT=$(jq -r '
[
.runs[] as $run
| ($run.tool.driver.rules // []) as $rules
| $run.results[]?
| . as $result
| (
(
if (($result.ruleIndex | type) == "number") then
($rules[$result.ruleIndex].properties["security-severity"] // empty)
else
empty
end
)
// ([
$rules[]?
| select((.id // "") == ($result.ruleId // ""))
| .properties["security-severity"]
][0] // empty)
// empty
) as $securitySeverity
| (try ($securitySeverity | tonumber) catch empty) as $score
| select($score != null and $score >= 7.0 and $score < 9.0)
] | length
' trivy-nightly.sarif)
MEDIUM_COUNT=$(jq -r '
[
.runs[] as $run
| ($run.tool.driver.rules // []) as $rules
| $run.results[]?
| . as $result
| (
(
if (($result.ruleIndex | type) == "number") then
($rules[$result.ruleIndex].properties["security-severity"] // empty)
else
empty
end
)
// ([
$rules[]?
| select((.id // "") == ($result.ruleId // ""))
| .properties["security-severity"]
][0] // empty)
// empty
) as $securitySeverity
| (try ($securitySeverity | tonumber) catch empty) as $score
| select($score != null and $score >= 4.0 and $score < 7.0)
] | length
' trivy-nightly.sarif)
{
echo "- Structured SARIF counts: CRITICAL=${CRITICAL_COUNT}, HIGH=${HIGH_COUNT}, MEDIUM=${MEDIUM_COUNT}"
} >> "$GITHUB_STEP_SUMMARY"
# List all Critical/High/Medium findings with details for triage
# shellcheck disable=SC2016
LIST_FINDINGS='
.runs[] as $run
| ($run.tool.driver.rules // []) as $rules
| $run.results[]?
| . as $result
| (
(
if (($result.ruleIndex | type) == "number") then
($rules[$result.ruleIndex] // {})
else
{}
end
) as $ruleByIndex
| (
[$rules[]? | select((.id // "") == ($result.ruleId // ""))][0] // {}
) as $ruleById
| ($ruleByIndex // $ruleById) as $rule
| ($rule.properties["security-severity"] // null) as $sev
| (try ($sev | tonumber) catch null) as $score
| select($score != null and $score >= 4.0)
| {
id: ($result.ruleId // "unknown"),
score: $score,
severity: (
if $score >= 9.0 then "CRITICAL"
elif $score >= 7.0 then "HIGH"
else "MEDIUM"
end
),
message: ($result.message.text // $rule.shortDescription.text // "no description")[0:120]
}
)
'
echo ""
echo "=== Vulnerability Details ==="
jq -r "[ ${LIST_FINDINGS} ] | sort_by(-.score) | .[] | \"\\(.severity) (\\(.score)): \\(.id) — \\(.message)\"" trivy-nightly.sarif || true
echo "============================="
echo ""
if [ "$CRITICAL_COUNT" -gt 0 ]; then
echo "❌ Critical vulnerabilities found in nightly build (${CRITICAL_COUNT})"
{
echo ""
echo "### ❌ Critical CVEs blocking nightly"
echo '```'
jq -r "[ ${LIST_FINDINGS} | select(.severity == \"CRITICAL\") ] | sort_by(-.score) | .[] | \"\\(.id) (score: \\(.score)): \\(.message)\"" trivy-nightly.sarif || true
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
exit 1
fi
echo "✅ No critical vulnerabilities found"
if [ "$HIGH_COUNT" -gt 0 ]; then
echo "❌ High vulnerabilities found in nightly build (${HIGH_COUNT})"
{
echo ""
echo "### ❌ High CVEs blocking nightly"
echo '```'
jq -r "[ ${LIST_FINDINGS} | select(.severity == \"HIGH\") ] | sort_by(-.score) | .[] | \"\\(.id) (score: \\(.score)): \\(.message)\"" trivy-nightly.sarif || true
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
exit 1
fi
if [ "$MEDIUM_COUNT" -gt 0 ]; then
echo "::warning::Medium vulnerabilities found in nightly build (${MEDIUM_COUNT}). Non-blocking by policy; triage with SLA per .github/security-severity-policy.yml"
{
echo ""
echo "### ⚠️ Medium CVEs (non-blocking)"
echo '```'
jq -r "[ ${LIST_FINDINGS} | select(.severity == \"MEDIUM\") ] | sort_by(-.score) | .[] | \"\\(.id) (score: \\(.score)): \\(.message)\"" trivy-nightly.sarif || true
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
fi
echo "✅ No Critical/High vulnerabilities found"

View File

@@ -12,6 +12,10 @@ concurrency:
group: ${{ github.workflow }}-${{ inputs.pr_number || github.event.pull_request.number }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: write
jobs:
validate:
name: Validate history-rewrite checklist (conditional)
@@ -21,7 +25,7 @@ jobs:
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Validate PR checklist (only for history-rewrite changes)
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
env:
PR_NUMBER: ${{ inputs.pr_number }}
with:

View File

@@ -28,15 +28,17 @@ jobs:
(github.event.workflow_run.head_branch == 'main' || github.event.workflow_run.head_branch == 'development')
steps:
- name: Set up Node (for github-script)
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: ${{ env.NODE_VERSION }}
- name: Propagate Changes
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
env:
CURRENT_BRANCH: ${{ github.event.workflow_run.head_branch || github.ref_name }}
CURRENT_SHA: ${{ github.event.workflow_run.head_sha || github.sha }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CHARON_TOKEN: ${{ secrets.CHARON_TOKEN }}
with:
script: |
const currentBranch = process.env.CURRENT_BRANCH || context.ref.replace('refs/heads/', '');
@@ -133,7 +135,9 @@ jobs:
const sensitive = files.some(fn => configPaths.some(sp => fn.startsWith(sp) || fn.includes(sp)));
if (sensitive) {
core.info(`${src} -> ${base} contains sensitive changes (${files.join(', ')}). Skipping automatic propagation.`);
const preview = files.slice(0, 25).join(', ');
const suffix = files.length > 25 ? ` …(+${files.length - 25} more)` : '';
core.info(`${src} -> ${base} contains sensitive changes (${preview}${suffix}). Skipping automatic propagation.`);
return;
}
} catch (error) {
@@ -203,6 +207,3 @@ jobs:
await createPR('development', targetBranch);
}
}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CHARON_TOKEN: ${{ secrets.CHARON_TOKEN }}

View File

@@ -3,6 +3,9 @@ name: Quality Checks
on:
pull_request:
push:
branches:
- nightly
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -13,11 +16,33 @@ permissions:
checks: write
env:
GO_VERSION: '1.26.0'
GO_VERSION: '1.26.2'
NODE_VERSION: '24.12.0'
GOTOOLCHAIN: auto
jobs:
auth-route-protection-contract:
name: Auth Route Protection Contract
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
ref: ${{ github.sha }}
- name: Set up Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: backend/go.sum
- name: Run auth protection contract tests
run: |
set -euo pipefail
cd backend
go test ./internal/api/routes -run 'TestRegister_StateChangingRoutesRequireAuthentication|TestRegister_StateChangingRoutesDenyByDefaultWithExplicitAllowlist|TestRegister_AuthenticatedRoutes' -count=1 -v
codecov-trigger-parity-guard:
name: Codecov Trigger/Comment Parity Guard
runs-on: ubuntu-latest
@@ -113,23 +138,34 @@ jobs:
} >> "$GITHUB_ENV"
- name: Set up Go
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: backend/go.sum
- name: Repo health check
run: |
bash "scripts/repo_health_check.sh"
- name: Install gotestsum
run: go install gotest.tools/gotestsum@v1.13.0
- name: Run Go tests
id: go-tests
working-directory: ${{ github.workspace }}
env:
CGO_ENABLED: 1
run: |
bash "scripts/go-test-coverage.sh" 2>&1 | tee backend/test-output.txt
exit "${PIPESTATUS[0]}"
bash "scripts/go-test-coverage.sh" 2>&1 | tee backend/test-output.txt; exit "${PIPESTATUS[0]}"
- name: Upload test output artifact
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: backend-test-output
path: backend/test-output.txt
retention-days: 7
- name: Go Test Summary
if: always()
@@ -206,11 +242,12 @@ jobs:
PERF_MAX_MS_GETSTATUS_P95_PARALLEL: 1500ms
PERF_MAX_MS_LISTDECISIONS_P95: 2000ms
run: |
go test -run TestPerf -v ./internal/api/handlers -count=1 2>&1 | tee perf-output.txt; PERF_STATUS="${PIPESTATUS[0]}"
{
echo "## 🔍 Running performance assertions (TestPerf)"
go test -run TestPerf -v ./internal/api/handlers -count=1 | tee perf-output.txt
cat perf-output.txt
} >> "$GITHUB_STEP_SUMMARY"
exit "${PIPESTATUS[0]}"
exit "$PERF_STATUS"
frontend-quality:
name: Frontend (React)
@@ -225,12 +262,18 @@ jobs:
bash "scripts/repo_health_check.sh"
- name: Set up Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
cache-dependency-path: frontend/package-lock.json
- name: Verify lockfile integrity and audit dependencies
working-directory: frontend
run: |
npm ci --ignore-scripts
npm audit --audit-level=critical
- name: Check if frontend was modified in PR
id: check-frontend
run: |
@@ -272,8 +315,7 @@ jobs:
id: frontend-tests
working-directory: ${{ github.workspace }}
run: |
bash scripts/frontend-test-coverage.sh 2>&1 | tee frontend/test-output.txt
exit "${PIPESTATUS[0]}"
bash scripts/frontend-test-coverage.sh 2>&1 | tee frontend/test-output.txt; exit "${PIPESTATUS[0]}"
- name: Frontend Test Summary
if: always()

View File

@@ -20,6 +20,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event.workflow_run.event || github.event_name }}-${{ github.event.workflow_run.head_branch || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
rate-limit-integration:
name: Rate Limiting Integration
@@ -31,7 +34,7 @@ jobs:
- name: Build Docker image (Local)
run: |
echo "Building image locally for integration tests..."
docker build -t charon:local .
docker build -t charon:local --build-arg CI="${CI:-false}" .
echo "✅ Successfully built charon:local"
- name: Run rate limit integration tests
@@ -68,7 +71,7 @@ jobs:
echo "### Caddy Admin Config (rate_limit handlers)"
echo '```json'
curl -s http://localhost:2119/config 2>/dev/null | grep -A 20 '"handler":"rate_limit"' | head -30 || echo "Could not retrieve Caddy config"
curl -s http://localhost:2119/config/ 2>/dev/null | grep -A 20 '"handler":"rate_limit"' | head -30 || echo "Could not retrieve Caddy config"
echo '```'
echo ""

View File

@@ -10,7 +10,7 @@ concurrency:
cancel-in-progress: false
env:
GO_VERSION: '1.26.0'
GO_VERSION: '1.26.2'
NODE_VERSION: '24.12.0'
GOTOOLCHAIN: auto
@@ -20,6 +20,7 @@ permissions:
jobs:
goreleaser:
if: ${{ !contains(github.ref_name, '-candidate') && !contains(github.ref_name, '-rc') }}
runs-on: ubuntu-latest
env:
# Use the built-in GITHUB_TOKEN by default for GitHub API operations.
@@ -32,13 +33,26 @@ jobs:
with:
fetch-depth: 0
- name: Enforce PR-2 release promotion guard
env:
REPO_VARS_JSON: ${{ toJSON(vars) }}
run: |
PR2_GATE_STATUS="$(printf '%s' "$REPO_VARS_JSON" | jq -r '.CHARON_PR2_GATES_PASSED // "false"')"
if [[ "$PR2_GATE_STATUS" != "true" ]]; then
echo "::error::Releasable tag promotion is blocked until PR-2 security/retirement gates pass."
echo "::error::Set repository variable CHARON_PR2_GATES_PASSED=true only after PR-2 approval."
exit 1
fi
- name: Set up Go
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: backend/go.sum
- name: Set up Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: ${{ env.NODE_VERSION }}
@@ -53,7 +67,7 @@ jobs:
- name: Install Cross-Compilation Tools (Zig)
# Security: Pinned to full SHA for supply chain security
uses: goto-bus-stop/setup-zig@abea47f85e598557f500fa1fd2ab7464fcb39406 # v2
uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2.2.1
with:
version: 0.13.0
@@ -61,7 +75,7 @@ jobs:
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6
uses: goreleaser/goreleaser-action@e24998b8b67b290c2fa8b7c14fcfa7de2c5c9b8c # v7
with:
distribution: goreleaser
version: '~> v2.5'

View File

@@ -14,6 +14,9 @@ permissions:
pull-requests: write
issues: write
env:
GO_VERSION: '1.26.2'
jobs:
renovate:
runs-on: ubuntu-latest
@@ -24,8 +27,13 @@ jobs:
with:
fetch-depth: 1
- name: Set up Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version: ${{ env.GO_VERSION }}
- name: Run Renovate
uses: renovatebot/github-action@d65ef9e20512193cc070238b49c3873a361cd50c # v46.1.1
uses: renovatebot/github-action@83ec54fee49ab67d9cd201084c1ff325b4b462e4 # v46.1.10
with:
configurationFile: .github/renovate.json
token: ${{ secrets.RENOVATE_TOKEN || secrets.GITHUB_TOKEN }}

View File

@@ -30,7 +30,7 @@ jobs:
echo "GITHUB_TOKEN=${{ secrets.CHARON_TOKEN }}" >> "$GITHUB_ENV"
fi
- name: Prune renovate branches
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
github-token: ${{ env.GITHUB_TOKEN }}
script: |

View File

@@ -9,6 +9,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref_name }}
cancel-in-progress: true
permissions:
contents: read
jobs:
repo_health:
name: Repo health
@@ -34,7 +37,7 @@ jobs:
- name: Upload health output
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: repo-health-output
path: |

View File

@@ -4,35 +4,44 @@
name: Security Scan (PR)
on:
workflow_run:
workflows: ["Docker Build, Publish & Test"]
types: [completed]
workflow_dispatch:
inputs:
pr_number:
description: 'PR number to scan (optional)'
required: false
description: 'PR number to scan'
required: true
type: string
pull_request:
push:
branches: [main]
concurrency:
group: security-pr-${{ github.event.workflow_run.event || github.event_name }}-${{ github.event.workflow_run.head_branch || github.ref }}
group: security-pr-${{ github.event_name == 'workflow_run' && github.event.workflow_run.event || github.event_name }}-${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_branch || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
security-scan:
name: Trivy Binary Scan
runs-on: ubuntu-latest
timeout-minutes: 10
# Run for: manual dispatch, PR builds, or any push builds from docker-build
# Run for manual dispatch, direct PR/push, or successful upstream workflow_run
if: >-
github.event_name == 'workflow_dispatch' ||
github.event_name == 'pull_request' ||
((github.event.workflow_run.event == 'push' || github.event.workflow_run.pull_requests[0].number != null) &&
(github.event.workflow_run.status != 'completed' || github.event.workflow_run.conclusion == 'success'))
github.event_name == 'push' ||
(github.event_name == 'workflow_run' &&
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.status == 'completed' &&
github.event.workflow_run.conclusion == 'success')
permissions:
contents: read
pull-requests: write
security-events: write
actions: read
@@ -41,27 +50,65 @@ jobs:
# actions/checkout v4.2.2
uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98
with:
ref: ${{ github.event.workflow_run.head_sha || github.sha }}
ref: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.sha }}
- name: Extract PR number from workflow_run
id: pr-info
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
# Manual dispatch - use input or fail gracefully
if [[ -n "${{ inputs.pr_number }}" ]]; then
echo "pr_number=${{ inputs.pr_number }}" >> "$GITHUB_OUTPUT"
echo "✅ Using manually provided PR number: ${{ inputs.pr_number }}"
else
echo "⚠️ No PR number provided for manual dispatch"
echo "pr_number=" >> "$GITHUB_OUTPUT"
fi
if [[ "${{ github.event_name }}" == "push" ]]; then
echo "pr_number=" >> "$GITHUB_OUTPUT"
echo "is_push=true" >> "$GITHUB_OUTPUT"
echo "✅ Push event detected; using local image path"
exit 0
fi
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
echo "pr_number=${{ github.event.pull_request.number }}" >> "$GITHUB_OUTPUT"
echo "is_push=false" >> "$GITHUB_OUTPUT"
echo "✅ Pull request event detected: PR #${{ github.event.pull_request.number }}"
exit 0
fi
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
INPUT_PR_NUMBER="${{ inputs.pr_number }}"
if [[ -z "${INPUT_PR_NUMBER}" ]]; then
echo "❌ workflow_dispatch requires inputs.pr_number"
exit 1
fi
if [[ ! "${INPUT_PR_NUMBER}" =~ ^[0-9]+$ ]]; then
echo "❌ reason_category=invalid_input"
echo "reason=workflow_dispatch pr_number must be digits-only"
exit 1
fi
PR_NUMBER="${INPUT_PR_NUMBER}"
echo "pr_number=${PR_NUMBER}" >> "$GITHUB_OUTPUT"
echo "is_push=false" >> "$GITHUB_OUTPUT"
echo "✅ Using manually provided PR number: ${PR_NUMBER}"
exit 0
fi
if [[ "${{ github.event_name }}" == "workflow_run" ]]; then
if [[ "${{ github.event.workflow_run.event }}" != "pull_request" ]]; then
# Explicit contract validation happens in the dedicated guard step.
echo "pr_number=" >> "$GITHUB_OUTPUT"
echo "is_push=false" >> "$GITHUB_OUTPUT"
exit 0
fi
if [[ -n "${{ github.event.workflow_run.pull_requests[0].number || '' }}" ]]; then
echo "pr_number=${{ github.event.workflow_run.pull_requests[0].number }}" >> "$GITHUB_OUTPUT"
echo "is_push=false" >> "$GITHUB_OUTPUT"
echo "✅ Found PR number from workflow_run payload: ${{ github.event.workflow_run.pull_requests[0].number }}"
exit 0
fi
fi
# Extract PR number from context
HEAD_SHA="${{ github.event.workflow_run.head_sha || github.event.pull_request.head.sha || github.sha }}"
HEAD_SHA="${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.event.pull_request.head.sha || github.sha }}"
echo "🔍 Looking for PR with head SHA: ${HEAD_SHA}"
# Query GitHub API for PR associated with this commit
@@ -73,21 +120,38 @@ jobs:
if [[ -n "${PR_NUMBER}" ]]; then
echo "pr_number=${PR_NUMBER}" >> "$GITHUB_OUTPUT"
echo "is_push=false" >> "$GITHUB_OUTPUT"
echo "✅ Found PR number: ${PR_NUMBER}"
else
echo "⚠️ Could not find PR number for SHA: ${HEAD_SHA}"
echo "pr_number=" >> "$GITHUB_OUTPUT"
echo " Could not determine PR number for workflow_run SHA: ${HEAD_SHA}"
exit 1
fi
# Check if this is a push event (not a PR)
if [[ "${{ github.event_name }}" == "push" || "${{ github.event.workflow_run.event }}" == "push" || -z "${PR_NUMBER}" ]]; then
HEAD_BRANCH="${{ github.event.workflow_run.head_branch || github.ref_name }}"
echo "is_push=true" >> "$GITHUB_OUTPUT"
echo "✅ Detected push build from branch: ${HEAD_BRANCH}"
else
echo "is_push=false" >> "$GITHUB_OUTPUT"
- name: Validate workflow_run trust boundary and event contract
if: github.event_name == 'workflow_run'
run: |
if [[ "${{ github.event.workflow_run.name }}" != "Docker Build, Publish & Test" ]]; then
echo "❌ reason_category=unexpected_upstream_workflow"
echo "workflow_name=${{ github.event.workflow_run.name }}"
exit 1
fi
if [[ "${{ github.event.workflow_run.event }}" != "pull_request" ]]; then
echo "❌ reason_category=unsupported_upstream_event"
echo "upstream_event=${{ github.event.workflow_run.event }}"
echo "run_id=${{ github.event.workflow_run.id }}"
exit 1
fi
if [[ "${{ github.event.workflow_run.head_repository.full_name }}" != "${{ github.repository }}" ]]; then
echo "❌ reason_category=untrusted_upstream_repository"
echo "upstream_head_repository=${{ github.event.workflow_run.head_repository.full_name }}"
echo "expected_repository=${{ github.repository }}"
exit 1
fi
echo "✅ workflow_run trust boundary and event contract validated"
- name: Build Docker image (Local)
if: github.event_name == 'push' || github.event_name == 'pull_request'
run: |
@@ -97,95 +161,149 @@ jobs:
- name: Check for PR image artifact
id: check-artifact
if: (steps.pr-info.outputs.pr_number != '' || steps.pr-info.outputs.is_push == 'true') && github.event_name != 'push' && github.event_name != 'pull_request'
if: github.event_name == 'workflow_run' || github.event_name == 'workflow_dispatch'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Determine artifact name based on event type
if [[ "${{ steps.pr-info.outputs.is_push }}" == "true" ]]; then
ARTIFACT_NAME="push-image"
else
PR_NUMBER="${{ steps.pr-info.outputs.pr_number }}"
ARTIFACT_NAME="pr-image-${PR_NUMBER}"
PR_NUMBER="${{ steps.pr-info.outputs.pr_number }}"
if [[ ! "${PR_NUMBER}" =~ ^[0-9]+$ ]]; then
echo "❌ reason_category=invalid_input"
echo "reason=Resolved PR number must be digits-only"
exit 1
fi
RUN_ID="${{ github.event.workflow_run.id }}"
ARTIFACT_NAME="pr-image-${PR_NUMBER}"
RUN_ID="${{ github.event_name == 'workflow_run' && github.event.workflow_run.id || '' }}"
echo "🔍 Checking for artifact: ${ARTIFACT_NAME}"
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
# For manual dispatch, find the most recent workflow run with this artifact
RUN_ID=$(gh api \
# Manual replay path: find latest successful docker-build pull_request run for this PR.
RUNS_JSON=$(gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/${{ github.repository }}/actions/workflows/docker-build.yml/runs?status=success&per_page=10" \
--jq '.workflow_runs[0].id // empty' 2>/dev/null || echo "")
"/repos/${{ github.repository }}/actions/workflows/docker-build.yml/runs?event=pull_request&status=success&per_page=100" 2>&1)
RUNS_STATUS=$?
if [[ ${RUNS_STATUS} -ne 0 ]]; then
echo "❌ reason_category=api_error"
echo "reason=Failed to query workflow runs for PR lookup"
echo "upstream_run_id=unknown"
echo "artifact_name=${ARTIFACT_NAME}"
echo "api_output=${RUNS_JSON}"
exit 1
fi
RUN_ID=$(printf '%s' "${RUNS_JSON}" | jq -r --argjson pr "${PR_NUMBER}" '.workflow_runs[] | select((.pull_requests // []) | any(.number == $pr)) | .id' | head -n 1)
if [[ -z "${RUN_ID}" ]]; then
echo "⚠️ No successful workflow runs found"
echo "artifact_exists=false" >> "$GITHUB_OUTPUT"
exit 0
echo "❌ reason_category=not_found"
echo "reason=No successful docker-build pull_request run found for PR #${PR_NUMBER}"
echo "upstream_run_id=unknown"
echo "artifact_name=${ARTIFACT_NAME}"
exit 1
fi
elif [[ -z "${RUN_ID}" ]]; then
# If triggered by push/pull_request, RUN_ID is empty. Find recent run for this commit.
HEAD_SHA="${{ github.event.workflow_run.head_sha || github.event.pull_request.head.sha || github.sha }}"
echo "🔍 Searching for workflow run for SHA: ${HEAD_SHA}"
# Retry a few times as the run might be just starting or finishing
for i in {1..3}; do
RUN_ID=$(gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/${{ github.repository }}/actions/workflows/docker-build.yml/runs?head_sha=${HEAD_SHA}&status=success&per_page=1" \
--jq '.workflow_runs[0].id // empty' 2>/dev/null || echo "")
if [[ -n "${RUN_ID}" ]]; then break; fi
echo "⏳ Waiting for workflow run to appear/complete... ($i/3)"
sleep 5
done
fi
echo "run_id=${RUN_ID}" >> "$GITHUB_OUTPUT"
# Check if the artifact exists in the workflow run
ARTIFACT_ID=$(gh api \
ARTIFACTS_JSON=$(gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/${{ github.repository }}/actions/runs/${RUN_ID}/artifacts" \
--jq ".artifacts[] | select(.name == \"${ARTIFACT_NAME}\") | .id" 2>/dev/null || echo "")
"/repos/${{ github.repository }}/actions/runs/${RUN_ID}/artifacts" 2>&1)
ARTIFACTS_STATUS=$?
if [[ -n "${ARTIFACT_ID}" ]]; then
echo "artifact_exists=true" >> "$GITHUB_OUTPUT"
echo "artifact_id=${ARTIFACT_ID}" >> "$GITHUB_OUTPUT"
echo "✅ Found artifact: ${ARTIFACT_NAME} (ID: ${ARTIFACT_ID})"
else
echo "artifact_exists=false" >> "$GITHUB_OUTPUT"
echo "⚠️ Artifact not found: ${ARTIFACT_NAME}"
echo " This is expected for non-PR builds or if the image was not uploaded"
if [[ ${ARTIFACTS_STATUS} -ne 0 ]]; then
echo "❌ reason_category=api_error"
echo "reason=Failed to query artifacts for upstream run"
echo "upstream_run_id=${RUN_ID}"
echo "artifact_name=${ARTIFACT_NAME}"
echo "api_output=${ARTIFACTS_JSON}"
exit 1
fi
- name: Skip if no artifact
if: ((steps.pr-info.outputs.pr_number == '' && steps.pr-info.outputs.is_push != 'true') || steps.check-artifact.outputs.artifact_exists != 'true') && github.event_name != 'push' && github.event_name != 'pull_request'
run: |
echo " Skipping security scan - no PR image artifact available"
echo "This is expected for:"
echo " - Pushes to main/release branches"
echo " - PRs where Docker build failed"
echo " - Manual dispatch without PR number"
exit 0
ARTIFACT_ID=$(printf '%s' "${ARTIFACTS_JSON}" | jq -r --arg name "${ARTIFACT_NAME}" '.artifacts[] | select(.name == $name) | .id' | head -n 1)
if [[ -z "${ARTIFACT_ID}" ]]; then
echo "❌ reason_category=not_found"
echo "reason=Required artifact was not found"
echo "upstream_run_id=${RUN_ID}"
echo "artifact_name=${ARTIFACT_NAME}"
exit 1
fi
{
echo "artifact_exists=true"
echo "artifact_id=${ARTIFACT_ID}"
echo "artifact_name=${ARTIFACT_NAME}"
} >> "$GITHUB_OUTPUT"
echo "✅ Found artifact: ${ARTIFACT_NAME} (ID: ${ARTIFACT_ID})"
- name: Download PR image artifact
if: steps.check-artifact.outputs.artifact_exists == 'true'
if: github.event_name == 'workflow_run' || github.event_name == 'workflow_dispatch'
# actions/download-artifact v4.1.8
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131
uses: actions/download-artifact@484a0b528fb4d7bd804637ccb632e47a0e638317
with:
name: ${{ steps.pr-info.outputs.is_push == 'true' && 'push-image' || format('pr-image-{0}', steps.pr-info.outputs.pr_number) }}
name: ${{ steps.check-artifact.outputs.artifact_name }}
run-id: ${{ steps.check-artifact.outputs.run_id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Load Docker image
if: steps.check-artifact.outputs.artifact_exists == 'true'
if: github.event_name == 'workflow_run' || github.event_name == 'workflow_dispatch'
id: load-image
run: |
echo "📦 Loading Docker image..."
docker load < charon-pr-image.tar
echo "✅ Docker image loaded"
if [[ ! -r "charon-pr-image.tar" ]]; then
echo "❌ ERROR: Artifact image tar is missing or unreadable"
exit 1
fi
MANIFEST_TAGS=""
if tar -tf charon-pr-image.tar | grep -qx "manifest.json"; then
MANIFEST_TAGS=$(tar -xOf charon-pr-image.tar manifest.json 2>/dev/null | jq -r '.[]?.RepoTags[]?' 2>/dev/null | sed '/^$/d' || true)
else
echo "⚠️ manifest.json not found in artifact tar; will try docker-load-image-id fallback"
fi
LOAD_OUTPUT=$(docker load < charon-pr-image.tar 2>&1)
echo "${LOAD_OUTPUT}"
SOURCE_IMAGE_REF=""
SOURCE_RESOLUTION_MODE=""
while IFS= read -r tag; do
[[ -z "${tag}" ]] && continue
if docker image inspect "${tag}" >/dev/null 2>&1; then
SOURCE_IMAGE_REF="${tag}"
SOURCE_RESOLUTION_MODE="manifest_tag"
break
fi
done <<< "${MANIFEST_TAGS}"
if [[ -z "${SOURCE_IMAGE_REF}" ]]; then
LOAD_IMAGE_ID=$(printf '%s\n' "${LOAD_OUTPUT}" | sed -nE 's/^Loaded image ID: (sha256:[0-9a-f]+)$/\1/p' | head -n1)
if [[ -n "${LOAD_IMAGE_ID}" ]] && docker image inspect "${LOAD_IMAGE_ID}" >/dev/null 2>&1; then
SOURCE_IMAGE_REF="${LOAD_IMAGE_ID}"
SOURCE_RESOLUTION_MODE="load_image_id"
fi
fi
if [[ -z "${SOURCE_IMAGE_REF}" ]]; then
echo "❌ ERROR: Could not resolve a valid image reference from manifest tags or docker load image ID"
exit 1
fi
docker tag "${SOURCE_IMAGE_REF}" "charon:artifact"
{
echo "source_image_ref=${SOURCE_IMAGE_REF}"
echo "source_resolution_mode=${SOURCE_RESOLUTION_MODE}"
echo "image_ref=charon:artifact"
} >> "$GITHUB_OUTPUT"
echo "✅ Docker image resolved via ${SOURCE_RESOLUTION_MODE} and tagged as charon:artifact"
docker images | grep charon
- name: Extract charon binary from container
@@ -214,31 +332,10 @@ jobs:
exit 0
fi
# Normalize image name for reference
IMAGE_NAME=$(echo "${{ github.repository_owner }}/charon" | tr '[:upper:]' '[:lower:]')
if [[ "${{ steps.pr-info.outputs.is_push }}" == "true" ]]; then
BRANCH_NAME="${{ github.event.workflow_run.head_branch }}"
if [[ -z "${BRANCH_NAME}" ]]; then
echo "❌ ERROR: Branch name is empty for push build"
exit 1
fi
# Normalize branch name for Docker tag (replace / and other special chars with -)
# This matches docker/metadata-action behavior: type=ref,event=branch
TAG_SAFE_BRANCH="${BRANCH_NAME//\//-}"
IMAGE_REF="ghcr.io/${IMAGE_NAME}:${TAG_SAFE_BRANCH}"
elif [[ -n "${{ steps.pr-info.outputs.pr_number }}" ]]; then
IMAGE_REF="ghcr.io/${IMAGE_NAME}:pr-${{ steps.pr-info.outputs.pr_number }}"
else
echo "❌ ERROR: Cannot determine image reference"
echo " - is_push: ${{ steps.pr-info.outputs.is_push }}"
echo " - pr_number: ${{ steps.pr-info.outputs.pr_number }}"
echo " - branch: ${{ github.event.workflow_run.head_branch }}"
exit 1
fi
# Validate the image reference format
if [[ ! "${IMAGE_REF}" =~ ^ghcr\.io/[a-z0-9_-]+/[a-z0-9_-]+:[a-zA-Z0-9._-]+$ ]]; then
echo "❌ ERROR: Invalid image reference format: ${IMAGE_REF}"
# For workflow_run artifact path, always use locally tagged image from loaded artifact.
IMAGE_REF="${{ steps.load-image.outputs.image_ref }}"
if [[ -z "${IMAGE_REF}" ]]; then
echo "❌ ERROR: Loaded artifact image reference is empty"
exit 1
fi
@@ -267,8 +364,8 @@ jobs:
- name: Run Trivy filesystem scan (SARIF output)
if: steps.check-artifact.outputs.artifact_exists == 'true' || github.event_name == 'push' || github.event_name == 'pull_request'
# aquasecurity/trivy-action v0.33.1
uses: aquasecurity/trivy-action@c1824fd6edce30d7ab345a9989de00bbd46ef284
# aquasecurity/trivy-action 0.35.0
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1
with:
scan-type: 'fs'
scan-ref: ${{ steps.extract.outputs.binary_path }}
@@ -277,19 +374,30 @@ jobs:
severity: 'CRITICAL,HIGH,MEDIUM'
continue-on-error: true
- name: Check Trivy SARIF output exists
if: always() && (steps.check-artifact.outputs.artifact_exists == 'true' || github.event_name == 'push' || github.event_name == 'pull_request')
id: trivy-sarif-check
run: |
if [[ -f trivy-binary-results.sarif ]]; then
echo "exists=true" >> "$GITHUB_OUTPUT"
else
echo "exists=false" >> "$GITHUB_OUTPUT"
echo " No Trivy SARIF output found; skipping SARIF/artifact upload steps"
fi
- name: Upload Trivy SARIF to GitHub Security
if: steps.check-artifact.outputs.artifact_exists == 'true' || github.event_name == 'push' || github.event_name == 'pull_request'
if: always() && steps.trivy-sarif-check.outputs.exists == 'true'
# github/codeql-action v4
uses: github/codeql-action/upload-sarif@5e7a52feb2a3dfb87f88be2af33b9e2275f48de6
uses: github/codeql-action/upload-sarif@34950e1b113b30df4edee1a6d3a605242df0c40b
with:
sarif_file: 'trivy-binary-results.sarif'
category: ${{ steps.pr-info.outputs.is_push == 'true' && format('security-scan-{0}', github.event.workflow_run.head_branch) || format('security-scan-pr-{0}', steps.pr-info.outputs.pr_number) }}
category: ${{ steps.pr-info.outputs.is_push == 'true' && format('security-scan-{0}', github.event_name == 'workflow_run' && github.event.workflow_run.head_branch || github.ref_name) || format('security-scan-pr-{0}', steps.pr-info.outputs.pr_number) }}
continue-on-error: true
- name: Run Trivy filesystem scan (fail on CRITICAL/HIGH)
if: steps.check-artifact.outputs.artifact_exists == 'true' || github.event_name == 'push' || github.event_name == 'pull_request'
# aquasecurity/trivy-action v0.33.1
uses: aquasecurity/trivy-action@c1824fd6edce30d7ab345a9989de00bbd46ef284
# aquasecurity/trivy-action 0.35.0
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1
with:
scan-type: 'fs'
scan-ref: ${{ steps.extract.outputs.binary_path }}
@@ -298,11 +406,11 @@ jobs:
exit-code: '1'
- name: Upload scan artifacts
if: always() && (steps.check-artifact.outputs.artifact_exists == 'true' || github.event_name == 'push' || github.event_name == 'pull_request')
if: always() && steps.trivy-sarif-check.outputs.exists == 'true'
# actions/upload-artifact v4.4.3
uses: actions/upload-artifact@47309c993abb98030a35d55ef7ff34b7fa1074b5
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
with:
name: ${{ steps.pr-info.outputs.is_push == 'true' && format('security-scan-{0}', github.event.workflow_run.head_branch) || format('security-scan-pr-{0}', steps.pr-info.outputs.pr_number) }}
name: ${{ steps.pr-info.outputs.is_push == 'true' && format('security-scan-{0}', github.event_name == 'workflow_run' && github.event.workflow_run.head_branch || github.ref_name) || format('security-scan-pr-{0}', steps.pr-info.outputs.pr_number) }}
path: |
trivy-binary-results.sarif
retention-days: 14
@@ -312,7 +420,7 @@ jobs:
run: |
{
if [[ "${{ steps.pr-info.outputs.is_push }}" == "true" ]]; then
echo "## 🔒 Security Scan Results - Branch: ${{ github.event.workflow_run.head_branch }}"
echo "## 🔒 Security Scan Results - Branch: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_branch || github.ref_name }}"
else
echo "## 🔒 Security Scan Results - PR #${{ steps.pr-info.outputs.pr_number }}"
fi

View File

@@ -6,7 +6,7 @@ name: Weekly Security Rebuild
on:
schedule:
- cron: '0 2 * * 0' # Sundays at 02:00 UTC
- cron: '0 12 * * 2' # Tuesdays at 12:00 UTC
workflow_dispatch:
inputs:
force_rebuild:
@@ -19,6 +19,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
permissions:
contents: read
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository_owner }}/charon
@@ -36,16 +39,21 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
# Explicitly fetch the current HEAD of the ref at run time, not the
# SHA that was frozen when this scheduled job was queued. Without this,
# a queued job can run days later with stale code.
ref: ${{ github.ref_name }}
- name: Normalize image name
run: |
echo "IMAGE_NAME=$(echo "${{ env.IMAGE_NAME }}" | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_ENV"
- name: Set up QEMU
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Resolve Debian base image digest
id: base-image
@@ -56,7 +64,7 @@ jobs:
echo "Base image digest: $DIGEST"
- name: Log in to Container Registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -64,7 +72,7 @@ jobs:
- name: Extract metadata
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
@@ -72,7 +80,7 @@ jobs:
- name: Build Docker image (NO CACHE)
id: build
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7
with:
context: .
platforms: linux/amd64
@@ -88,38 +96,41 @@ jobs:
BASE_IMAGE=${{ steps.base-image.outputs.digest }}
- name: Run Trivy vulnerability scanner (CRITICAL+HIGH)
uses: aquasecurity/trivy-action@c1824fd6edce30d7ab345a9989de00bbd46ef284 # 0.34.0
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 0.35.0
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
format: 'table'
severity: 'CRITICAL,HIGH'
exit-code: '1' # Fail workflow if vulnerabilities found
version: 'v0.70.0'
continue-on-error: true
- name: Run Trivy vulnerability scanner (SARIF)
id: trivy-sarif
uses: aquasecurity/trivy-action@c1824fd6edce30d7ab345a9989de00bbd46ef284 # 0.34.0
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 0.35.0
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
format: 'sarif'
output: 'trivy-weekly-results.sarif'
severity: 'CRITICAL,HIGH,MEDIUM'
version: 'v0.70.0'
- name: Upload Trivy results to GitHub Security
uses: github/codeql-action/upload-sarif@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
with:
sarif_file: 'trivy-weekly-results.sarif'
- name: Run Trivy vulnerability scanner (JSON for artifact)
uses: aquasecurity/trivy-action@c1824fd6edce30d7ab345a9989de00bbd46ef284 # 0.34.0
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 0.35.0
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
format: 'json'
output: 'trivy-weekly-results.json'
severity: 'CRITICAL,HIGH,MEDIUM,LOW'
version: 'v0.70.0'
- name: Upload Trivy JSON results
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: trivy-weekly-scan-${{ github.run_number }}
path: trivy-weekly-results.json

View File

@@ -11,6 +11,8 @@ on:
type: string
pull_request:
push:
branches:
- main
concurrency:
group: supply-chain-pr-${{ github.event.workflow_run.event || github.event_name }}-${{ github.event.workflow_run.head_branch || github.ref }}
@@ -264,7 +266,7 @@ jobs:
# Generate SBOM using official Anchore action (auto-updated by Renovate)
- name: Generate SBOM
if: steps.set-target.outputs.image_name != ''
uses: anchore/sbom-action@28d71544de8eaf1b958d335707167c5f783590ad # v0.22.2
uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
id: sbom
with:
image: ${{ steps.set-target.outputs.image_name }}
@@ -279,19 +281,19 @@ jobs:
echo "component_count=${COMPONENT_COUNT}" >> "$GITHUB_OUTPUT"
echo "✅ SBOM generated with ${COMPONENT_COUNT} components"
# Scan for vulnerabilities using manual Grype installation (pinned to v0.107.1)
# Scan for vulnerabilities using manual Grype installation (pinned to v0.110.0)
- name: Install Grype
if: steps.set-target.outputs.image_name != ''
run: |
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin v0.107.1
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin v0.111.0
- name: Scan for vulnerabilities
if: steps.set-target.outputs.image_name != ''
id: grype-scan
run: |
echo "🔍 Scanning SBOM for vulnerabilities..."
grype sbom:sbom.cyclonedx.json -o json > grype-results.json
grype sbom:sbom.cyclonedx.json -o sarif > grype-results.sarif
grype sbom:sbom.cyclonedx.json --config .grype.yaml -o json > grype-results.json
grype sbom:sbom.cyclonedx.json --config .grype.yaml -o sarif > grype-results.sarif
- name: Debug Output Files
if: steps.set-target.outputs.image_name != ''
@@ -337,9 +339,30 @@ jobs:
echo " Low: ${LOW_COUNT}"
echo " Total: ${TOTAL_COUNT}"
- name: Security severity policy summary
if: steps.set-target.outputs.image_name != ''
run: |
CRITICAL_COUNT="${{ steps.vuln-summary.outputs.critical_count }}"
HIGH_COUNT="${{ steps.vuln-summary.outputs.high_count }}"
MEDIUM_COUNT="${{ steps.vuln-summary.outputs.medium_count }}"
{
echo "## 🔐 Supply Chain Severity Policy"
echo ""
echo "- Blocking: Critical, High"
echo "- Medium: non-blocking by default (report + triage SLA)"
echo "- Policy file: .github/security-severity-policy.yml"
echo ""
echo "Current scan counts: Critical=${CRITICAL_COUNT}, High=${HIGH_COUNT}, Medium=${MEDIUM_COUNT}"
} >> "$GITHUB_STEP_SUMMARY"
if [[ "${MEDIUM_COUNT}" -gt 0 ]]; then
echo "::warning::${MEDIUM_COUNT} medium vulnerabilities found. Non-blocking by policy; create/maintain triage issue with SLA per .github/security-severity-policy.yml"
fi
- name: Upload SARIF to GitHub Security
if: steps.check-artifact.outputs.artifact_found == 'true'
uses: github/codeql-action/upload-sarif@9e907b5e64f6b83e7804b09294d44122997950d6 # v4
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
continue-on-error: true
with:
sarif_file: grype-results.sarif
@@ -348,7 +371,7 @@ jobs:
- name: Upload supply chain artifacts
if: steps.set-target.outputs.image_name != ''
# actions/upload-artifact v4.6.0
uses: actions/upload-artifact@47309c993abb98030a35d55ef7ff34b7fa1074b5
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
with:
name: ${{ steps.pr-number.outputs.is_push == 'true' && format('supply-chain-{0}', steps.sanitize.outputs.branch) || format('supply-chain-pr-{0}', steps.pr-number.outputs.pr_number) }}
path: |
@@ -358,9 +381,12 @@ jobs:
- name: Comment on PR
if: steps.set-target.outputs.image_name != '' && steps.pr-number.outputs.is_push != 'true' && steps.pr-number.outputs.pr_number != ''
continue-on-error: true
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
PR_NUMBER="${{ steps.pr-number.outputs.pr_number }}"
COMPONENT_COUNT="${{ steps.sbom-count.outputs.component_count }}"
CRITICAL_COUNT="${{ steps.vuln-summary.outputs.critical_count }}"
@@ -406,37 +432,47 @@ jobs:
EOF
)
# Find and update existing comment or create new one
COMMENT_ID=$(gh api \
# Fetch existing comments — skip gracefully on 403 / permission errors
COMMENTS_JSON=""
if ! COMMENTS_JSON=$(gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" \
--jq '.[] | select(.body | contains("Supply Chain Verification Results")) | .id' | head -1)
"/repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" 2>/dev/null); then
echo "⚠️ Cannot access PR comments (likely token permissions / fork / event context). Skipping PR comment."
exit 0
fi
if [[ -n "${COMMENT_ID}" ]]; then
COMMENT_ID=$(echo "${COMMENTS_JSON}" | jq -r '.[] | select(.body | contains("Supply Chain Verification Results")) | .id' | head -1)
if [[ -n "${COMMENT_ID:-}" && "${COMMENT_ID}" != "null" ]]; then
echo "📝 Updating existing comment..."
gh api \
--method PATCH \
if ! gh api --method PATCH \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/${{ github.repository }}/issues/comments/${COMMENT_ID}" \
-f body="${COMMENT_BODY}"
-f body="${COMMENT_BODY}"; then
echo "⚠️ Failed to update comment (permissions?). Skipping."
exit 0
fi
else
echo "📝 Creating new comment..."
gh api \
--method POST \
if ! gh api --method POST \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" \
-f body="${COMMENT_BODY}"
-f body="${COMMENT_BODY}"; then
echo "⚠️ Failed to create comment (permissions?). Skipping."
exit 0
fi
fi
echo "✅ PR comment posted"
- name: Fail on critical vulnerabilities
- name: Fail on Critical/High vulnerabilities
if: steps.set-target.outputs.image_name != ''
run: |
CRITICAL_COUNT="${{ steps.vuln-summary.outputs.critical_count }}"
HIGH_COUNT="${{ steps.vuln-summary.outputs.high_count }}"
if [[ "${CRITICAL_COUNT}" -gt 0 ]]; then
echo "🚨 Found ${CRITICAL_COUNT} CRITICAL vulnerabilities!"
@@ -444,4 +480,10 @@ jobs:
exit 1
fi
echo "✅ No critical vulnerabilities found"
if [[ "${HIGH_COUNT}" -gt 0 ]]; then
echo "🚨 Found ${HIGH_COUNT} HIGH vulnerabilities!"
echo "Please review the vulnerability report and address high severity issues before merging."
exit 1
fi
echo "✅ No Critical/High vulnerabilities found"

View File

@@ -119,7 +119,7 @@ jobs:
# Generate SBOM using official Anchore action (auto-updated by Renovate)
- name: Generate and Verify SBOM
if: steps.image-check.outputs.exists == 'true'
uses: anchore/sbom-action@28d71544de8eaf1b958d335707167c5f783590ad # v0.22.2
uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
with:
image: ghcr.io/${{ github.repository_owner }}/charon:${{ steps.tag.outputs.tag }}
format: cyclonedx-json
@@ -144,7 +144,7 @@ jobs:
- name: Upload SBOM Artifact
if: steps.image-check.outputs.exists == 'true' && always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: sbom-${{ steps.tag.outputs.tag }}
path: sbom-verify.cyclonedx.json
@@ -233,7 +233,7 @@ jobs:
# Scan for vulnerabilities using official Anchore action (auto-updated by Renovate)
- name: Scan for Vulnerabilities
if: steps.validate-sbom.outputs.valid == 'true'
uses: anchore/scan-action@7037fa011853d5a11690026fb85feee79f4c946c # v7.3.2
uses: anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2 # v7.4.0
id: scan
with:
sbom: sbom-verify.cyclonedx.json
@@ -324,7 +324,7 @@ jobs:
- name: Upload Vulnerability Scan Artifact
if: steps.validate-sbom.outputs.valid == 'true' && always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: vulnerability-scan-${{ steps.tag.outputs.tag }}
path: |
@@ -362,7 +362,7 @@ jobs:
if: |
github.event_name == 'pull_request' ||
(github.event_name == 'workflow_run' && github.event.workflow_run.event == 'pull_request')
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
result-encoding: string
script: |

View File

@@ -2,7 +2,7 @@ name: Update GeoLite2 Checksum
on:
schedule:
- cron: '0 2 * * 1' # Weekly on Mondays at 2 AM UTC
- cron: '0 2 * * 0' # Weekly on Sundays at 2 AM UTC
workflow_dispatch:
permissions:
@@ -105,7 +105,7 @@ jobs:
- name: Create Pull Request
if: steps.checksum.outputs.needs_update == 'true'
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
with:
title: "chore(docker): update GeoLite2-Country.mmdb checksum"
body: |
@@ -141,7 +141,8 @@ jobs:
---
**Auto-generated by:** `.github/workflows/update-geolite2.yml`
**Trigger:** Scheduled weekly check (Mondays 2 AM UTC)
- **Trigger:** Scheduled weekly check (Sundays 2 AM UTC)
base: development
branch: bot/update-geolite2-checksum
delete-branch: true
commit-message: |
@@ -160,7 +161,7 @@ jobs:
- name: Report failure via GitHub Issue
if: failure()
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
const errorType = '${{ steps.checksum.outputs.error }}' || 'unknown';
@@ -182,7 +183,7 @@ jobs:
### Workflow Details
- **Run URL:** ${runUrl}
- **Triggered:** ${context.eventName === 'schedule' ? 'Scheduled (weekly)' : 'Manual dispatch'}
- **Triggered:** ${context.eventName === 'schedule' ? 'Scheduled (weekly, Sundays)' : 'Manual dispatch'}
- **Timestamp:** ${new Date().toISOString()}
### Required Actions

View File

@@ -20,6 +20,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event.workflow_run.event || github.event_name }}-${{ github.event.workflow_run.head_branch || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
waf-integration:
name: Coraza WAF Integration
@@ -31,7 +34,7 @@ jobs:
- name: Build Docker image (Local)
run: |
echo "Building image locally for integration tests..."
docker build -t charon:local .
docker build -t charon:local --build-arg CI="${CI:-false}" .
echo "✅ Successfully built charon:local"
- name: Run WAF integration tests

View File

@@ -5,9 +5,9 @@ name: Weekly Nightly to Main Promotion
on:
schedule:
# Every Monday at 10:30 UTC (5:30am EST / 6:30am EDT)
# Every Monday at 12:00 UTC (7:00am EST / 8:00am EDT)
# Offset from nightly sync (09:00 UTC) to avoid schedule race and allow validation completion.
- cron: '30 10 * * 1'
- cron: '0 12 * * 1'
workflow_dispatch:
inputs:
reason:
@@ -47,7 +47,7 @@ jobs:
steps:
- name: Check Nightly Workflow Status
id: check
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
const skipCheck = '${{ inputs.skip_workflow_check }}' === 'true';
@@ -200,8 +200,8 @@ jobs:
runs-on: ubuntu-latest
if: needs.check-nightly-health.outputs.is_healthy == 'true'
outputs:
pr_number: ${{ steps.create-pr.outputs.pr_number }}
pr_url: ${{ steps.create-pr.outputs.pr_url }}
pr_number: ${{ steps.create-pr.outputs.pr_number || steps.existing-pr.outputs.pr_number }}
pr_url: ${{ steps.create-pr.outputs.pr_url || steps.existing-pr.outputs.pr_url }}
skipped: ${{ steps.check-diff.outputs.skipped }}
steps:
@@ -274,7 +274,7 @@ jobs:
- name: Check for Existing PR
id: existing-pr
if: steps.check-diff.outputs.skipped != 'true'
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
const { data: pulls } = await github.rest.pulls.list({
@@ -297,7 +297,7 @@ jobs:
- name: Create Promotion PR
id: create-pr
if: steps.check-diff.outputs.skipped != 'true' && steps.existing-pr.outputs.exists != 'true'
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
const fs = require('fs');
@@ -399,7 +399,7 @@ jobs:
- name: Update Existing PR
if: steps.check-diff.outputs.skipped != 'true' && steps.existing-pr.outputs.exists == 'true'
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
const prNumber = ${{ steps.existing-pr.outputs.pr_number }};
@@ -425,7 +425,7 @@ jobs:
contents: read
steps:
- name: Dispatch missing required workflows on nightly head
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
const owner = context.repo.owner;
@@ -483,7 +483,7 @@ jobs:
steps:
- name: Create Failure Issue
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
const isHealthy = '${{ needs.check-nightly-health.outputs.is_healthy }}';

18
.gitignore vendored
View File

@@ -78,6 +78,11 @@ backend/node_modules/
backend/package.json
backend/package-lock.json
# Root-level artifact files (non-documentation)
FIREFOX_E2E_FIXES_SUMMARY.md
verify-security-state-for-ui-tests
categories.txt
# -----------------------------------------------------------------------------
# Databases
# -----------------------------------------------------------------------------
@@ -297,6 +302,7 @@ docs/plans/current_spec_notes.md
tests/etc/passwd
trivy-image-report.json
trivy-fs-report.json
trivy-report.json
backend/# Tools Configuration.md
docs/plans/requirements.md
docs/plans/design.md
@@ -306,4 +312,14 @@ frontend/temp**
playwright-output/**
validation-evidence/**
.github/agents/# Tools Configuration.md
docs/plans/codecove_patch_report.md
docs/reports/codecove_patch_report.md
vuln-results.json
test_output.txt
coverage_results.txt
final-results.json
new-results.json
scan_output.json
coverage_output.txt
frontend/lint_output.txt
lefthook_out.txt
backend/test_out.txt

View File

@@ -4,60 +4,618 @@
# Documentation: https://github.com/anchore/grype#specifying-matches-to-ignore
ignore:
# CVE-2026-22184: zlib Global Buffer Overflow in untgz utility
# Severity: CRITICAL
# Package: zlib 1.3.1-r2 (Alpine Linux base image)
# Status: No upstream fix available as of 2026-01-16
# CVE-2026-2673: OpenSSL TLS 1.3 server key exchange group downgrade
# Severity: HIGH (CVSS 7.5)
# Packages: libcrypto3 3.5.5-r0 and libssl3 3.5.5-r0 (Alpine apk)
# Status: No upstream fix available — Alpine 3.23 still ships libcrypto3/libssl3 3.5.5-r0 as of 2026-03-18
#
# Vulnerability Details:
# - Global buffer overflow in TGZfname() function
# - Unbounded strcpy() allows attacker-controlled archive names
# - Can lead to memory corruption, DoS, potential RCE
# - When DEFAULT is in the TLS 1.3 group configuration, the OpenSSL server may select
# a weaker key exchange group than preferred, enabling a limited key exchange downgrade.
# - Only affects systems acting as a raw TLS 1.3 server using OpenSSL's server-side group negotiation.
#
# Risk Assessment: ACCEPTED (Low exploitability in Charon context)
# - Charon does not use untgz utility directly
# - No untrusted tar archive processing in application code
# - Attack surface limited to OS-level utilities
# - Multiple layers of containerization and isolation
# Root Cause (No Fix Available):
# - Alpine upstream has not published a patched libcrypto3/libssl3 for Alpine 3.23.
# - Checked: Alpine 3.23 still ships libcrypto3/libssl3 3.5.5-r0 as of 2026-03-18.
# - Fix path: once Alpine publishes a patched libcrypto3/libssl3, rebuild the Docker image
# and remove this suppression.
#
# Mitigation:
# - Monitor Alpine Linux security feed daily for zlib patches
# - Container runs with minimal privileges (no-new-privileges)
# - Read-only filesystem where possible
# - Network isolation via Docker networks
# Risk Assessment: ACCEPTED (No upstream fix; limited exposure in Charon context)
# - Charon terminates TLS at the Caddy layer — the Go backend does not act as a raw TLS 1.3 server.
# - The vulnerability requires the affected application to directly configure TLS 1.3 server
# group negotiation via OpenSSL, which Charon does not do.
# - Container-level isolation reduces the attack surface further.
#
# Mitigation (active while suppression is in effect):
# - Monitor Alpine security advisories: https://security.alpinelinux.org/vuln/CVE-2026-2673
# - Weekly CI security rebuild (security-weekly-rebuild.yml) flags any new CVEs in the full image.
#
# Review:
# - Daily checks for Alpine security updates
# - Automatic re-scan via CI/CD on every commit
# - Manual review scheduled for 2026-01-23 (7 days)
# - Reviewed 2026-03-18 (initial suppression): no upstream fix available. Set 30-day review.
# - Extended 2026-04-04: Alpine 3.23 still ships 3.5.5-r0. No upstream fix available.
# - Next review: 2026-05-18. Remove suppression immediately once upstream fixes.
#
# Removal Criteria:
# - Alpine releases zlib 1.3.1-r3 or higher with CVE fix
# - OR upstream zlib project releases patched version
# - Remove this suppression immediately after fix available
# - Alpine publishes a patched version of libcrypto3 and libssl3
# - Rebuild Docker image and verify CVE-2026-2673 no longer appears in grype-results.json
# - Remove both these entries and the corresponding .trivyignore entry simultaneously
#
# References:
# - CVE: https://nvd.nist.gov/vuln/detail/CVE-2026-22184
# - Alpine Security: https://security.alpinelinux.org/
# - GitHub Issue: https://github.com/Wikid82/Charon/issues/TBD
- vulnerability: CVE-2026-22184
# - CVE-2026-2673: https://nvd.nist.gov/vuln/detail/CVE-2026-2673
# - Alpine security tracker: https://security.alpinelinux.org/vuln/CVE-2026-2673
- vulnerability: CVE-2026-2673
package:
name: zlib
version: "1.3.1-r2"
type: apk # Alpine package
name: libcrypto3
version: "3.5.5-r0"
type: apk
reason: |
CRITICAL buffer overflow in untgz utility. No fix available from Alpine
as of 2026-01-16. Risk accepted: Charon does not directly use untgz or
process untrusted tar archives. Attack surface limited to base OS utilities.
Monitoring Alpine security feed for upstream patch.
expiry: "2026-01-23" # Re-evaluate in 7 days
HIGH — OpenSSL TLS 1.3 server key exchange group downgrade in libcrypto3 3.5.5-r0 (Alpine base image).
No upstream fix: Alpine 3.23 still ships libcrypto3 3.5.5-r0 as of 2026-03-18. Charon
terminates TLS at the Caddy layer; the Go backend does not act as a raw TLS 1.3 server.
Risk accepted pending Alpine upstream patch.
expiry: "2026-05-18" # Extended 2026-04-04: Alpine 3.23 still ships 3.5.5-r0. Next review 2026-05-18.
# Action items when this suppression expires:
# 1. Check Alpine security feed: https://security.alpinelinux.org/
# 2. Check zlib releases: https://github.com/madler/zlib/releases
# 3. If fix available: Update Dockerfile, rebuild, remove suppression
# 4. If no fix: Extend expiry by 7 days, document justification
# 5. If extended 3+ times: Escalate to security team for review
# 1. Check Alpine security tracker: https://security.alpinelinux.org/vuln/CVE-2026-2673
# 2. If a patched Alpine package is now available:
# a. Rebuild Docker image without suppression
# b. Run local security-scan-docker-image and confirm CVE is resolved
# c. Remove this suppression entry, the libssl3 entry below, and the .trivyignore entry
# 3. If no fix yet: Extend expiry by 1430 days and update the review comment above
# 4. If extended 3+ times: Open an issue to track the upstream status formally
# CVE-2026-2673 (libssl3) — see full justification in the libcrypto3 entry above
- vulnerability: CVE-2026-2673
package:
name: libssl3
version: "3.5.5-r0"
type: apk
reason: |
HIGH — OpenSSL TLS 1.3 server key exchange group downgrade in libssl3 3.5.5-r0 (Alpine base image).
No upstream fix: Alpine 3.23 still ships libssl3 3.5.5-r0 as of 2026-03-18. Charon
terminates TLS at the Caddy layer; the Go backend does not act as a raw TLS 1.3 server.
Risk accepted pending Alpine upstream patch.
expiry: "2026-05-18" # Extended 2026-04-04: see libcrypto3 entry above for action items.
# CVE-2026-31790: OpenSSL vulnerability in Alpine base image packages
# Severity: HIGH
# Packages: libcrypto3 3.5.5-r0 and libssl3 3.5.5-r0 (Alpine apk)
# Status: No upstream fix available — Alpine 3.23 still ships libcrypto3/libssl3 3.5.5-r0 as of 2026-04-09
#
# Root Cause (No Fix Available):
# - Alpine upstream has not published a patched libcrypto3/libssl3 for Alpine 3.23.
# - Checked: Alpine 3.23 still ships libcrypto3/libssl3 3.5.5-r0 as of 2026-04-09.
# - Fix path: once Alpine publishes a patched libcrypto3/libssl3, rebuild the Docker image
# and remove this suppression.
#
# Risk Assessment: ACCEPTED (No upstream fix; documented in SECURITY.md)
# - Charon terminates TLS at the Caddy layer — the Go backend does not act as a raw TLS server.
# - Container-level isolation reduces the attack surface further.
#
# Mitigation (active while suppression is in effect):
# - Monitor Alpine security advisories: https://security.alpinelinux.org/vuln/CVE-2026-31790
# - Weekly CI security rebuild (security-weekly-rebuild.yml) flags any new CVEs in the full image.
#
# Review:
# - Reviewed 2026-04-09 (initial suppression): no upstream fix available. Set 30-day review.
# - Next review: 2026-05-09. Remove suppression immediately once upstream fixes.
#
# Removal Criteria:
# - Alpine publishes a patched version of libcrypto3 and libssl3
# - Rebuild Docker image and verify CVE-2026-31790 no longer appears in grype-results.json
# - Remove both these entries and the corresponding .trivyignore entry simultaneously
#
# References:
# - CVE-2026-31790: https://nvd.nist.gov/vuln/detail/CVE-2026-31790
# - Alpine security tracker: https://security.alpinelinux.org/vuln/CVE-2026-31790
- vulnerability: CVE-2026-31790
package:
name: libcrypto3
version: "3.5.5-r0"
type: apk
reason: |
HIGH — OpenSSL vulnerability in libcrypto3 3.5.5-r0 (Alpine base image).
No upstream fix: Alpine 3.23 still ships libcrypto3 3.5.5-r0 as of 2026-04-09. Charon
terminates TLS at the Caddy layer; the Go backend does not act as a raw TLS server.
Risk accepted pending Alpine upstream patch. Documented in SECURITY.md.
expiry: "2026-05-09" # Reviewed 2026-04-09: no upstream fix available. Next review 2026-05-09.
# Action items when this suppression expires:
# 1. Check Alpine security tracker: https://security.alpinelinux.org/vuln/CVE-2026-31790
# 2. If a patched Alpine package is now available:
# a. Rebuild Docker image without suppression
# b. Run local security-scan-docker-image and confirm CVE is resolved
# c. Remove this suppression entry, the libssl3 entry below, and the .trivyignore entry
# 3. If no fix yet: Extend expiry by 1430 days and update the review comment above
# 4. If extended 3+ times: Open an issue to track the upstream status formally
# CVE-2026-31790 (libssl3) — see full justification in the libcrypto3 entry above
- vulnerability: CVE-2026-31790
package:
name: libssl3
version: "3.5.5-r0"
type: apk
reason: |
HIGH — OpenSSL vulnerability in libssl3 3.5.5-r0 (Alpine base image).
No upstream fix: Alpine 3.23 still ships libssl3 3.5.5-r0 as of 2026-04-09. Charon
terminates TLS at the Caddy layer; the Go backend does not act as a raw TLS server.
Risk accepted pending Alpine upstream patch. Documented in SECURITY.md.
expiry: "2026-05-09" # Reviewed 2026-04-09: see libcrypto3 entry above for action items.
# GHSA-69x3-g4r3-p962 / CVE-2026-25793: Nebula ECDSA Signature Malleability
# Severity: HIGH (CVSS 8.1)
# Package: github.com/slackhq/nebula v1.9.7 (embedded in /usr/bin/caddy via smallstep/certificates)
# Status: Fix exists in nebula v1.10.3 — smallstep/certificates cannot compile against v1.10+ APIs
#
# Vulnerability Details:
# - ECDSA signature malleability in nebula allows potential authentication bypass via
# crafted certificate signatures (CWE-347).
# - CVSSv3: AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N (CVSS 8.1)
#
# Root Cause (Third-Party Binary + Upstream API Incompatibility):
# - Charon does not use nebula directly. The library is compiled into the Caddy binary
# via the caddy-security plugin → smallstep/certificates dependency chain.
# - Nebula v1.10.3 patches the vulnerability but removes legacy APIs that
# smallstep/certificates (through v0.30.2) depends on, causing compile failures.
# - Fix path: once smallstep/certificates releases a version compatible with nebula >= v1.10.3,
# update the Dockerfile and remove this suppression.
#
# Risk Assessment: ACCEPTED (No direct use + upstream API incompatibility blocks fix)
# - Charon does not use Nebula VPN PKI by default. The vulnerable code path is only
# reachable if Nebula-based certificate provisioning is explicitly configured.
# - The attack requires network access and a crafted certificate, which is not part of
# standard Charon deployment.
#
# Mitigation (active while suppression is in effect):
# - Monitor smallstep/certificates releases: https://github.com/smallstep/certificates/releases
# - Monitor nebula releases: https://github.com/slackhq/nebula/releases
# - Weekly CI security rebuild flags the moment a compatible upstream ships.
#
# Review:
# - Reviewed 2026-02-19 (initial suppression in .trivyignore): certificates v0.27.5 pins nebula v1.9.x.
# - Re-evaluated 2026-04-10: nebula v1.10.3 has the fix but certificates (through v0.30.2)
# uses legacy APIs removed in v1.10+. Still blocked. Set 30-day review.
# - Next review: 2026-05-10. Remove suppression once certificates ships with nebula >= v1.10.3.
#
# Removal Criteria:
# - smallstep/certificates releases a version compatible with nebula >= v1.10.3
# - Update Dockerfile nebula pin, rebuild, run security-scan-docker-image, confirm resolved
# - Remove this entry and the corresponding .trivyignore entry simultaneously
#
# References:
# - GHSA-69x3-g4r3-p962: https://github.com/advisories/GHSA-69x3-g4r3-p962
# - CVE-2026-25793: https://nvd.nist.gov/vuln/detail/CVE-2026-25793
# - Nebula releases: https://github.com/slackhq/nebula/releases
# - smallstep/certificates releases: https://github.com/smallstep/certificates/releases
- vulnerability: CVE-2026-25793
package:
name: github.com/slackhq/nebula
version: "v1.9.7"
type: go-module
reason: |
HIGH — ECDSA signature malleability in nebula v1.9.7 embedded in /usr/bin/caddy.
Fix exists in nebula v1.10.3 but smallstep/certificates (through v0.30.2) uses legacy APIs
removed in v1.10+, causing compile failures. Charon does not use Nebula VPN PKI by default.
Risk accepted; no remediation until smallstep/certificates ships with nebula >= v1.10.3.
Re-evaluated 2026-04-10: still blocked by upstream API incompatibility.
expiry: "2026-05-10" # Re-evaluated 2026-04-10: certificates through v0.30.2 incompatible with nebula v1.10+.
# GHSA-6g7g-w4f8-9c9x: buger/jsonparser Delete panic on malformed JSON (DoS)
# Severity: HIGH (CVSS 7.5)
# Package: github.com/buger/jsonparser v1.1.1 (embedded in /usr/local/bin/crowdsec and /usr/local/bin/cscli)
# Status: UPSTREAM FIX EXISTS (v1.1.2 released 2026-03-20) — awaiting CrowdSec to update dependency
# NOTE: As of 2026-04-20, grype v0.111.0 with fresh DB no longer flags this finding in the image.
# This suppression is retained as a safety net in case future DB updates re-surface it.
#
# Vulnerability Details:
# - The Delete function fails to validate offsets on malformed JSON input, producing a
# negative slice index and a runtime panic — denial of service (CWE-125).
# - CVSSv3: AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
#
# Root Cause (Third-Party Binary — Fix Exists Upstream, Not Yet in CrowdSec):
# - Charon does not use buger/jsonparser directly. It is compiled into CrowdSec binaries.
# - buger/jsonparser released v1.1.2 on 2026-03-20 fixing issue #275.
# - CrowdSec has not yet released a version built with buger/jsonparser v1.1.2.
# - Fix path: once CrowdSec updates their dependency and rebuilds, rebuild the Docker image
# and remove this suppression.
#
# Risk Assessment: ACCEPTED (Limited exploitability; fix exists upstream but not yet in CrowdSec)
# - The DoS vector requires passing malformed JSON to the vulnerable Delete function within
# CrowdSec's internal processing pipeline; this is not a direct attack surface in Charon.
# - CrowdSec's exposed surface is its HTTP API (not raw JSON stream parsing via this path).
#
# Mitigation (active while suppression is in effect):
# - Monitor CrowdSec releases for a build using buger/jsonparser >= v1.1.2.
# - CrowdSec releases: https://github.com/crowdsecurity/crowdsec/releases
# - Weekly CI security rebuild flags the moment a fixed image ships.
#
# Review:
# - Reviewed 2026-03-19 (initial suppression): no upstream fix. Set 30-day review.
# - Extended 2026-04-04: no upstream fix. buger/jsonparser issue #275 still open.
# - Updated 2026-04-20: buger/jsonparser v1.1.2 released 2026-03-20. CrowdSec not yet updated.
# Grype v0.111.0 with fresh DB (2026-04-20) no longer flags this finding. Suppression retained
# as a safety net. Next review: 2026-05-19 — remove if CrowdSec ships with v1.1.2+.
#
# Removal Criteria:
# - CrowdSec releases a version built with buger/jsonparser >= v1.1.2
# - Rebuild Docker image, run security-scan-docker-image, confirm finding is resolved
# - Remove this entry and the corresponding .trivyignore entry simultaneously
#
# References:
# - GHSA-6g7g-w4f8-9c9x: https://github.com/advisories/GHSA-6g7g-w4f8-9c9x
# - Upstream fix: https://github.com/buger/jsonparser/releases/tag/v1.1.2
# - golang/vulndb: https://github.com/golang/vulndb/issues/4514
# - CrowdSec releases: https://github.com/crowdsecurity/crowdsec/releases
- vulnerability: GHSA-6g7g-w4f8-9c9x
package:
name: github.com/buger/jsonparser
version: "v1.1.1"
type: go-module
reason: |
HIGH — DoS panic via malformed JSON in buger/jsonparser v1.1.1 embedded in CrowdSec binaries.
Upstream fix: buger/jsonparser v1.1.2 released 2026-03-20; CrowdSec has not yet updated their
dependency. Grype no longer flags this as of 2026-04-20 (fresh DB). Suppression retained as
safety net pending CrowdSec update. Charon does not use this package directly.
Updated 2026-04-20: fix v1.1.2 exists upstream; awaiting CrowdSec dependency update.
expiry: "2026-05-19" # Review 2026-05-19: remove if CrowdSec ships with buger/jsonparser >= v1.1.2.
# Action items when this suppression expires:
# 1. Check if CrowdSec has released a version with buger/jsonparser >= v1.1.2:
# https://github.com/crowdsecurity/crowdsec/releases
# 2. If CrowdSec has updated: rebuild Docker image, run security-scan-docker-image,
# and remove this suppression entry and the corresponding .trivyignore entry
# 3. If grype still does not flag it with fresh DB: consider removing the suppression as
# it may no longer be necessary
# 4. If no CrowdSec update yet: Extend expiry by 30 days
# GHSA-jqcq-xjh3-6g23: pgproto3/v2 DataRow.Decode panic on negative field length (DoS)
# Severity: HIGH (CVSS 7.5)
# Package: github.com/jackc/pgproto3/v2 v2.3.3 (embedded in /usr/local/bin/crowdsec and /usr/local/bin/cscli)
# Status: NO fix in pgproto3/v2 (archived/EOL) — fix path requires CrowdSec to migrate to pgx/v5
#
# Vulnerability Details:
# - DataRow.Decode does not validate field lengths; a malicious or compromised PostgreSQL server
# can send a negative field length causing a slice-bounds panic — denial of service (CWE-129).
# - CVSSv3: AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
#
# Root Cause (EOL Module + Third-Party Binary):
# - Charon does not use pgproto3/v2 directly nor communicate with PostgreSQL. The package
# is compiled into CrowdSec binaries for their internal database communication.
# - The pgproto3/v2 module is archived and EOL; no fix will be released. The fix path
# is migration to pgx/v5, which embeds an updated pgproto3/v3.
# - Fix path: once CrowdSec migrates to pgx/v5 and releases an updated binary, rebuild
# the Docker image and remove this suppression.
#
# Risk Assessment: ACCEPTED (Non-exploitable in Charon context + no upstream fix path)
# - The vulnerability requires a malicious PostgreSQL server response. Charon uses SQLite
# internally and does not run PostgreSQL. CrowdSec's database path is not exposed to
# external traffic in a standard Charon deployment.
# - The attack requires a compromised database server, which would imply full host compromise.
#
# Mitigation (active while suppression is in effect):
# - Monitor CrowdSec releases for pgx/v5 migration:
# https://github.com/crowdsecurity/crowdsec/releases
# - Weekly CI security rebuild flags the moment a fixed image ships.
#
# Review:
# - Reviewed 2026-03-19 (initial suppression): pgproto3/v2 is EOL; no fix exists or will exist.
# Waiting on CrowdSec to migrate to pgx/v5. Set 30-day review.
# - Extended 2026-04-04: CrowdSec has not migrated to pgx/v5 yet.
# - Next review: 2026-05-19. Remove suppression once CrowdSec ships with pgx/v5.
#
# Removal Criteria:
# - CrowdSec releases a version with pgx/v5 (pgproto3/v3) replacing pgproto3/v2
# - Rebuild Docker image, run security-scan-docker-image, confirm finding is resolved
# - Remove this entry and the corresponding .trivyignore entry simultaneously
#
# References:
# - GHSA-jqcq-xjh3-6g23: https://github.com/advisories/GHSA-jqcq-xjh3-6g23
# - pgproto3/v2 archive notice: https://github.com/jackc/pgproto3
# - pgx/v5 (replacement): https://github.com/jackc/pgx
# - CrowdSec releases: https://github.com/crowdsecurity/crowdsec/releases
- vulnerability: GHSA-jqcq-xjh3-6g23
package:
name: github.com/jackc/pgproto3/v2
version: "v2.3.3"
type: go-module
reason: |
HIGH — DoS panic via negative field length in pgproto3/v2 v2.3.3 embedded in CrowdSec binaries.
pgproto3/v2 is archived/EOL with no fix planned; fix path requires CrowdSec to migrate to pgx/v5.
Charon uses SQLite, not PostgreSQL; this code path is not reachable in a standard deployment.
Risk accepted; no remediation until CrowdSec ships with pgx/v5.
Reviewed 2026-03-19: pgproto3/v2 EOL confirmed; CrowdSec has not migrated to pgx/v5 yet.
expiry: "2026-05-19" # Extended 2026-04-04: no fix path until CrowdSec migrates to pgx/v5.
# Action items when this suppression expires:
# 1. Check CrowdSec releases for pgx/v5 migration:
# https://github.com/crowdsecurity/crowdsec/releases
# 2. Verify with: `go version -m /path/to/crowdsec | grep pgproto3`
# Expected: pgproto3/v3 (or no pgproto3 reference if fully replaced)
# 3. If CrowdSec has migrated:
# a. Rebuild Docker image and run local security-scan-docker-image
# b. Remove this suppression entry and the corresponding .trivyignore entry
# 4. If not yet migrated: Extend expiry by 30 days and update the review comment above
# 5. If extended 3+ times: Open an upstream issue on crowdsecurity/crowdsec requesting pgx/v5 migration
# GHSA-x6gf-mpr2-68h6 / CVE-2026-4427: pgproto3/v2 DataRow.Decode panic on negative field length (DoS)
# Severity: HIGH (CVSS 7.5)
# Package: github.com/jackc/pgproto3/v2 v2.3.3 (embedded in /usr/local/bin/crowdsec and /usr/local/bin/cscli)
# Status: NO fix in pgproto3/v2 (archived/EOL) — fix path requires CrowdSec to migrate to pgx/v5
# Note: This is the NVD/Red Hat advisory alias for the same underlying vulnerability as GHSA-jqcq-xjh3-6g23
#
# Vulnerability Details:
# - DataRow.Decode does not validate field lengths; a malicious or compromised PostgreSQL server
# can send a negative field length causing a slice-bounds panic — denial of service (CWE-129).
# - CVSSv3: AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H (CVSS 7.5)
#
# Root Cause (EOL Module + Third-Party Binary):
# - Same underlying vulnerability as GHSA-jqcq-xjh3-6g23; tracked separately by NVD/Red Hat as CVE-2026-4427.
# - Charon does not use pgproto3/v2 directly nor communicate with PostgreSQL. The package
# is compiled into CrowdSec binaries for their internal database communication.
# - The pgproto3/v2 module is archived and EOL; no fix will be released. The fix path
# is migration to pgx/v5, which embeds an updated pgproto3/v3.
# - Fix path: once CrowdSec migrates to pgx/v5 and releases an updated binary, rebuild
# the Docker image and remove this suppression.
#
# Risk Assessment: ACCEPTED (Non-exploitable in Charon context + no upstream fix path)
# - The vulnerability requires a malicious PostgreSQL server response. Charon uses SQLite
# internally and does not run PostgreSQL. CrowdSec's database path is not exposed to
# external traffic in a standard Charon deployment.
# - The attack requires a compromised database server, which would imply full host compromise.
#
# Mitigation (active while suppression is in effect):
# - Monitor CrowdSec releases for pgx/v5 migration:
# https://github.com/crowdsecurity/crowdsec/releases
# - Weekly CI security rebuild flags the moment a fixed image ships.
#
# Review:
# - Reviewed 2026-03-21 (initial suppression): pgproto3/v2 is EOL; no fix exists or will exist.
# Waiting on CrowdSec to migrate to pgx/v5. Set 30-day review. Sibling GHSA-jqcq-xjh3-6g23
# was already suppressed; this alias surfaced as a separate Grype match via NVD/Red Hat tracking.
# - Extended 2026-04-04: CrowdSec has not migrated to pgx/v5 yet.
# - Next review: 2026-05-21. Remove suppression once CrowdSec ships with pgx/v5.
#
# Removal Criteria:
# - Same as GHSA-jqcq-xjh3-6g23: CrowdSec releases a version with pgx/v5 replacing pgproto3/v2
# - Rebuild Docker image, run security-scan-docker-image, confirm both advisories are resolved
# - Remove this entry, GHSA-jqcq-xjh3-6g23 entry, and both .trivyignore entries simultaneously
#
# References:
# - GHSA-x6gf-mpr2-68h6: https://github.com/advisories/GHSA-x6gf-mpr2-68h6
# - CVE-2026-4427: https://nvd.nist.gov/vuln/detail/CVE-2026-4427
# - Red Hat: https://access.redhat.com/security/cve/CVE-2026-4427
# - pgproto3/v2 archive notice: https://github.com/jackc/pgproto3
# - pgx/v5 (replacement): https://github.com/jackc/pgx
# - CrowdSec releases: https://github.com/crowdsecurity/crowdsec/releases
- vulnerability: GHSA-x6gf-mpr2-68h6
package:
name: github.com/jackc/pgproto3/v2
version: "v2.3.3"
type: go-module
reason: |
HIGH — DoS panic via negative field length in pgproto3/v2 v2.3.3 embedded in CrowdSec binaries.
NVD/Red Hat alias (CVE-2026-4427) for the same underlying bug as GHSA-jqcq-xjh3-6g23.
pgproto3/v2 is archived/EOL with no fix planned; fix path requires CrowdSec to migrate to pgx/v5.
Charon uses SQLite, not PostgreSQL; this code path is not reachable in a standard deployment.
Risk accepted; no remediation until CrowdSec ships with pgx/v5.
Reviewed 2026-03-21: pgproto3/v2 EOL confirmed; CrowdSec has not migrated to pgx/v5 yet.
expiry: "2026-05-21" # Extended 2026-04-04: no fix path until CrowdSec migrates to pgx/v5.
# Action items when this suppression expires:
# 1. Check CrowdSec releases for pgx/v5 migration:
# https://github.com/crowdsecurity/crowdsec/releases
# 2. Verify with: `go version -m /path/to/crowdsec | grep pgproto3`
# Expected: pgproto3/v3 (or no pgproto3 reference if fully replaced)
# 3. If CrowdSec has migrated:
# a. Rebuild Docker image and run local security-scan-docker-image
# b. Remove this entry, GHSA-jqcq-xjh3-6g23 entry, and both .trivyignore entries
# 4. If not yet migrated: Extend expiry by 30 days and update the review comment above
# 5. If extended 3+ times: Open an upstream issue on crowdsecurity/crowdsec requesting pgx/v5 migration
# CVE-2026-32286: pgproto3/v2 buffer overflow in DataRow handling (DoS)
# Severity: HIGH (CVSS 7.5)
# Package: github.com/jackc/pgproto3/v2 v2.3.3 (embedded in /usr/local/bin/crowdsec and /usr/local/bin/cscli)
# Status: NO fix in pgproto3/v2 (archived/EOL) — fix path requires CrowdSec to migrate to pgx/v5
#
# Vulnerability Details:
# - Buffer overflow in pgproto3/v2 DataRow handling allows a malicious or compromised PostgreSQL
# server to trigger a denial of service via crafted protocol messages (CWE-120).
# - CVSSv3: AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H (CVSS 7.5)
#
# Root Cause (EOL Module + Third-Party Binary):
# - Same affected module as GHSA-jqcq-xjh3-6g23 and GHSA-x6gf-mpr2-68h6 — pgproto3/v2 v2.3.3
# is the final release (repository archived Jul 12, 2025). No fix will be released.
# - Charon does not use pgproto3/v2 directly nor communicate with PostgreSQL. The package
# is compiled into CrowdSec binaries for their internal database communication.
# - Fix exists only in pgproto3/v3 (used by pgx/v5). CrowdSec v1.7.7 (latest) still depends
# on pgx/v4 → pgproto3/v2. Dockerfile already applies best-effort mitigation (pgx/v4@v4.18.3).
# - Fix path: once CrowdSec migrates to pgx/v5, rebuild the Docker image and remove this suppression.
#
# Risk Assessment: ACCEPTED (Non-exploitable in Charon context + no upstream fix path)
# - The vulnerability requires a malicious PostgreSQL server response. Charon uses SQLite
# internally and does not run PostgreSQL. CrowdSec's database path is not exposed to
# external traffic in a standard Charon deployment.
# - CrowdSec's PostgreSQL code path is not directly exposed to untrusted network input in
# Charon's deployment.
#
# Mitigation (active while suppression is in effect):
# - Monitor CrowdSec releases for pgx/v5 migration:
# https://github.com/crowdsecurity/crowdsec/releases
# - Weekly CI security rebuild flags the moment a fixed image ships.
#
# Review:
# - Reviewed 2026-04-10 (initial suppression): pgproto3/v2 is EOL; no fix exists or will exist.
# Waiting on CrowdSec to migrate to pgx/v5. Set 90-day review.
# - Next review: 2026-07-09. Remove suppression once CrowdSec ships with pgx/v5.
#
# Removal Criteria:
# - Same as GHSA-jqcq-xjh3-6g23: CrowdSec releases a version with pgx/v5 replacing pgproto3/v2
# - Rebuild Docker image, run security-scan-docker-image, confirm all pgproto3/v2 advisories are resolved
# - Remove this entry, GHSA-jqcq-xjh3-6g23 entry, GHSA-x6gf-mpr2-68h6 entry, and all .trivyignore entries simultaneously
#
# References:
# - CVE-2026-32286: https://nvd.nist.gov/vuln/detail/CVE-2026-32286
# - pgproto3/v2 archive notice: https://github.com/jackc/pgproto3
# - pgx/v5 (replacement): https://github.com/jackc/pgx
# - CrowdSec releases: https://github.com/crowdsecurity/crowdsec/releases
- vulnerability: CVE-2026-32286
package:
name: github.com/jackc/pgproto3/v2
version: "v2.3.3"
type: go-module
reason: |
HIGH — Buffer overflow in pgproto3/v2 v2.3.3 DataRow handling, embedded in CrowdSec binaries.
pgproto3/v2 v2.3.3 is the final release (archived Jul 2025); no fix will be released.
Fix exists only in pgproto3/v3 (pgx/v5). CrowdSec v1.7.7 still depends on pgx/v4 → pgproto3/v2.
Charon uses SQLite, not PostgreSQL; this code path is not reachable in a standard deployment.
Risk accepted; no remediation until CrowdSec ships with pgx/v5.
Reviewed 2026-04-10: pgproto3/v2 EOL confirmed; CrowdSec has not migrated to pgx/v5 yet.
expiry: "2026-07-09" # Reviewed 2026-04-10: no fix path until CrowdSec migrates to pgx/v5. 90-day expiry.
# Action items when this suppression expires:
# 1. Check CrowdSec releases for pgx/v5 migration:
# https://github.com/crowdsecurity/crowdsec/releases
# 2. Verify with: `go version -m /path/to/crowdsec | grep pgproto3`
# Expected: pgproto3/v3 (or no pgproto3 reference if fully replaced)
# 3. If CrowdSec has migrated:
# a. Rebuild Docker image and run local security-scan-docker-image
# b. Remove this entry, GHSA-jqcq-xjh3-6g23 entry, GHSA-x6gf-mpr2-68h6 entry, and all .trivyignore entries
# 4. If not yet migrated: Extend expiry by 30 days and update the review comment above
# 5. If extended 3+ times: Open an upstream issue on crowdsecurity/crowdsec requesting pgx/v5 migration
# GHSA-pxq6-2prw-chj9 / CVE-2026-33997: Moby off-by-one error in plugin privilege validation
# Severity: MEDIUM (CVSS 6.8)
# Package: github.com/docker/docker v28.5.2+incompatible (go-module)
# Status: Fixed in moby/moby v29.3.1 — NO fix available for docker/docker import path
#
# Vulnerability Details:
# - Off-by-one error in Moby's plugin privilege validation allows potential privilege escalation
# via crafted plugin configurations.
#
# Root Cause (No Fix Available for Import Path):
# - Same import path issue as CVE-2026-34040. The fix exists in moby/moby v29.3.1 but not
# for the docker/docker import path that Charon uses.
# - Fix path: same dependency migration pattern as CVE-2026-34040 (if needed) or upstream fix.
#
# Risk Assessment: ACCEPTED (Not exploitable in Charon context)
# - Charon uses the Docker client SDK only (list containers). The vulnerability is in Docker's
# plugin privilege validation, which is server-side functionality.
# - Charon does not run a Docker daemon, install Docker plugins, or interact with plugin privileges.
#
# Mitigation (active while suppression is in effect):
# - Monitor docker/docker releases: https://github.com/moby/moby/releases
# - Weekly CI security rebuild flags the moment a fixed version ships.
#
# Review:
# - Reviewed 2026-03-30 (initial suppression): no fix for docker/docker import path. Set 30-day review.
# - Next review: 2026-04-30. Remove suppression once a fix is available for the docker/docker import path.
#
# Removal Criteria:
# - docker/docker publishes a patched version OR moby/moby/v2 stabilizes
# - Update dependency, rebuild, run security-scan-docker-image, confirm finding is resolved
# - Remove this entry and all corresponding .trivyignore entries simultaneously
#
# References:
# - GHSA-pxq6-2prw-chj9: https://github.com/advisories/GHSA-pxq6-2prw-chj9
# - CVE-2026-33997: https://nvd.nist.gov/vuln/detail/CVE-2026-33997
# - moby/moby releases: https://github.com/moby/moby/releases
- vulnerability: GHSA-pxq6-2prw-chj9
package:
name: github.com/docker/docker
version: "v28.5.2+incompatible"
type: go-module
reason: |
MEDIUM — Off-by-one error in Moby plugin privilege validation in docker/docker v28.5.2+incompatible.
Fixed in moby/moby v29.3.1 but no fix for docker/docker import path.
Charon uses Docker client SDK only (list containers); the vulnerability is in Docker's server-side
plugin privilege validation. Charon does not run a Docker daemon or install Docker plugins.
Risk accepted; no remediation path until docker/docker publishes a fix or moby/moby/v2 stabilizes.
Reviewed 2026-03-30: no patched release available for docker/docker import path.
expiry: "2026-04-30" # 30-day review: no fix for docker/docker import path. Extend in 30-day increments with documented justification.
# Action items when this suppression expires:
# 1. Check docker/docker and moby/moby releases: https://github.com/moby/moby/releases
# 2. Check if moby/moby/v2 has stabilized: https://github.com/moby/moby
# 3. If a fix has shipped for docker/docker import path OR moby/moby/v2 is stable:
# a. Update the dependency and rebuild Docker image
# b. Run local security-scan-docker-image and confirm finding is resolved
# c. Remove this entry and all corresponding .trivyignore entries
# 4. If no fix yet: Extend expiry by 30 days and update the review comment above
# 5. If extended 3+ times: Open an issue to track moby/moby/v2 migration feasibility
# GHSA-78h2-9frx-2jm8: go-jose JWE decryption panic (DoS)
# Severity: HIGH
# Packages: github.com/go-jose/go-jose/v3 v3.0.4 and github.com/go-jose/go-jose/v4 v4.1.3
# (embedded in /usr/bin/caddy)
# Status: Fix available in go-jose/v3 v3.0.5 and go-jose/v4 v4.1.4 — requires upstream Caddy rebuild
#
# Vulnerability Details:
# - JWE decryption can trigger a panic due to improper input validation, causing
# a denial-of-service condition (runtime crash).
#
# Root Cause (Third-Party Binary):
# - Charon does not use go-jose directly. The library is compiled into the Caddy binary
# shipped in the Docker image.
# - Fixes are available upstream (v3.0.5 and v4.1.4) but require a Caddy rebuild to pick up.
# - Fix path: once the upstream Caddy release includes the patched go-jose versions,
# rebuild the Docker image and remove these suppressions.
#
# Risk Assessment: ACCEPTED (No direct use + fix requires upstream rebuild)
# - Charon does not import or call go-jose functions; the library is only present as a
# transitive dependency inside the Caddy binary.
# - The attack vector requires crafted JWE input reaching Caddy's internal JWT handling,
# which is limited to authenticated admin-API paths not exposed in Charon deployments.
#
# Mitigation (active while suppression is in effect):
# - Monitor Caddy releases: https://github.com/caddyserver/caddy/releases
# - Weekly CI security rebuild flags the moment a fixed image ships.
#
# Review:
# - Reviewed 2026-04-05 (initial suppression): fix available upstream but not yet in Caddy release.
# Set 30-day review.
# - Next review: 2026-05-05. Remove suppression once Caddy ships with patched go-jose.
#
# Removal Criteria:
# - Caddy releases a version built with go-jose/v3 >= v3.0.5 and go-jose/v4 >= v4.1.4
# - Rebuild Docker image, run security-scan-docker-image, confirm finding is resolved
# - Remove both entries (v3 and v4) and any corresponding .trivyignore entries simultaneously
#
# References:
# - GHSA-78h2-9frx-2jm8: https://github.com/advisories/GHSA-78h2-9frx-2jm8
# - go-jose releases: https://github.com/go-jose/go-jose/releases
# - Caddy releases: https://github.com/caddyserver/caddy/releases
- vulnerability: GHSA-78h2-9frx-2jm8
package:
name: github.com/go-jose/go-jose/v3
version: "v3.0.4"
type: go-module
reason: |
HIGH — JWE decryption panic in go-jose v3.0.4 embedded in /usr/bin/caddy.
Fix available in v3.0.5 but requires upstream Caddy rebuild. Charon does not use go-jose
directly. Deferring to next Caddy release.
expiry: "2026-05-05" # 30-day review: remove once Caddy ships with go-jose/v3 >= v3.0.5.
# Action items when this suppression expires:
# 1. Check Caddy releases: https://github.com/caddyserver/caddy/releases
# 2. Verify with: `go version -m /usr/bin/caddy | grep go-jose`
# Expected: go-jose/v3 >= v3.0.5
# 3. If Caddy has updated:
# a. Rebuild Docker image and run local security-scan-docker-image
# b. Remove this entry, the v4 entry below, and any corresponding .trivyignore entries
# 4. If not yet updated: Extend expiry by 30 days and update the review comment above
# 5. If extended 3+ times: Open an upstream issue on caddyserver/caddy requesting go-jose update
# GHSA-78h2-9frx-2jm8 (go-jose/v4) — see full justification in the go-jose/v3 entry above
- vulnerability: GHSA-78h2-9frx-2jm8
package:
name: github.com/go-jose/go-jose/v4
version: "v4.1.3"
type: go-module
reason: |
HIGH — JWE decryption panic in go-jose v4.1.3 embedded in /usr/bin/caddy.
Fix available in v4.1.4 but requires upstream Caddy rebuild. Charon does not use go-jose
directly. Deferring to next Caddy release.
expiry: "2026-05-05" # 30-day review: see go-jose/v3 entry above for action items.
# Match exclusions (patterns to ignore during scanning)
# Use sparingly - prefer specific CVE suppressions above

View File

@@ -1,211 +0,0 @@
# NOTE: golangci-lint-fast now includes test files (_test.go) to catch security
# issues earlier. The fast config uses gosec with critical-only checks (G101,
# G110, G305, G401, G501, G502, G503) for acceptable performance.
# Last updated: 2026-02-02
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: end-of-file-fixer
exclude: '^(frontend/(coverage|dist|node_modules|\.vite)/|.*\.tsbuildinfo$)'
- id: trailing-whitespace
exclude: '^(frontend/(coverage|dist|node_modules|\.vite)/|.*\.tsbuildinfo$)'
- id: check-yaml
- id: check-added-large-files
args: ['--maxkb=2500']
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.10.0.1
hooks:
- id: shellcheck
name: shellcheck
exclude: '^(frontend/(coverage|dist|node_modules|\.vite)/|test-results|codeql-agent-results)/'
args: ['--severity=error']
- repo: https://github.com/rhysd/actionlint
rev: v1.7.10
hooks:
- id: actionlint
name: actionlint (GitHub Actions)
files: '^\.github/workflows/.*\.ya?ml$'
- repo: local
hooks:
- id: dockerfile-check
name: dockerfile validation
entry: tools/dockerfile_check.sh
language: script
files: "Dockerfile.*"
pass_filenames: true
- id: go-test-coverage
name: Go Test Coverage (Manual)
entry: scripts/go-test-coverage.sh
language: script
files: '\.go$'
pass_filenames: false
verbose: true
stages: [manual] # Only runs when explicitly called
- id: go-vet
name: Go Vet
entry: bash -c 'cd backend && go vet ./...'
language: system
files: '\.go$'
pass_filenames: false
- id: golangci-lint-fast
name: golangci-lint (Fast Linters - BLOCKING)
entry: scripts/pre-commit-hooks/golangci-lint-fast.sh
language: script
files: '\.go$'
# Test files are now included to catch security issues (gosec critical checks)
pass_filenames: false
description: "Runs fast, essential linters (staticcheck, govet, errcheck, ineffassign, unused, gosec critical) - BLOCKS commits on failure"
- id: check-version-match
name: Check .version matches latest Git tag
entry: bash -c 'scripts/check-version-match-tag.sh'
language: system
files: '\.version$'
pass_filenames: false
- id: check-lfs-large-files
name: Prevent large files that are not tracked by LFS
entry: bash scripts/pre-commit-hooks/check-lfs-for-large-files.sh
language: system
pass_filenames: false
verbose: true
always_run: true
- id: block-codeql-db-commits
name: Prevent committing CodeQL DB artifacts
entry: bash scripts/pre-commit-hooks/block-codeql-db-commits.sh
language: system
pass_filenames: false
verbose: true
always_run: true
- id: block-data-backups-commit
name: Prevent committing data/backups files
entry: bash scripts/pre-commit-hooks/block-data-backups-commit.sh
language: system
pass_filenames: false
verbose: true
always_run: true
# === MANUAL/CI-ONLY HOOKS ===
# These are slow and should only run on-demand or in CI
# Run manually with: pre-commit run golangci-lint-full --all-files
- id: go-test-race
name: Go Test Race (Manual)
entry: bash -c 'cd backend && go test -race ./...'
language: system
files: '\.go$'
pass_filenames: false
stages: [manual] # Only runs when explicitly called
- id: golangci-lint-full
name: golangci-lint (Full - Manual)
entry: scripts/pre-commit-hooks/golangci-lint-full.sh
language: script
files: '\.go$'
pass_filenames: false
stages: [manual] # Only runs when explicitly called
- id: hadolint
name: Hadolint Dockerfile Check (Manual)
entry: bash -c 'docker run --rm -i hadolint/hadolint < Dockerfile'
language: system
files: 'Dockerfile'
pass_filenames: false
stages: [manual] # Only runs when explicitly called
- id: frontend-type-check
name: Frontend TypeScript Check
entry: bash -c 'cd frontend && npm run type-check'
language: system
files: '^frontend/.*\.(ts|tsx)$'
pass_filenames: false
- id: frontend-lint
name: Frontend Lint (Fix)
entry: bash -c 'cd frontend && npm run lint -- --fix'
language: system
files: '^frontend/.*\.(ts|tsx|js|jsx)$'
pass_filenames: false
- id: frontend-test-coverage
name: Frontend Test Coverage (Manual)
entry: scripts/frontend-test-coverage.sh
language: script
files: '^frontend/.*\\.(ts|tsx|js|jsx)$'
pass_filenames: false
verbose: true
stages: [manual]
- id: security-scan
name: Security Vulnerability Scan (Manual)
entry: scripts/security-scan.sh
language: script
files: '(\.go$|go\.mod$|go\.sum$)'
pass_filenames: false
verbose: true
stages: [manual] # Only runs when explicitly called
- id: codeql-go-scan
name: CodeQL Go Security Scan (Manual - Slow)
entry: scripts/pre-commit-hooks/codeql-go-scan.sh
language: script
files: '\.go$'
pass_filenames: false
verbose: true
stages: [manual] # Performance: 30-60s, only run on-demand
- id: codeql-js-scan
name: CodeQL JavaScript/TypeScript Security Scan (Manual - Slow)
entry: scripts/pre-commit-hooks/codeql-js-scan.sh
language: script
files: '^frontend/.*\.(ts|tsx|js|jsx)$'
pass_filenames: false
verbose: true
stages: [manual] # Performance: 30-60s, only run on-demand
- id: codeql-check-findings
name: Block HIGH/CRITICAL CodeQL Findings
entry: scripts/pre-commit-hooks/codeql-check-findings.sh
language: script
pass_filenames: false
verbose: true
stages: [manual] # Only runs after CodeQL scans
- id: codeql-parity-check
name: CodeQL Suite/Trigger Parity Guard (Manual)
entry: scripts/ci/check-codeql-parity.sh
language: script
pass_filenames: false
verbose: true
stages: [manual]
- id: gorm-security-scan
name: GORM Security Scanner (Manual)
entry: scripts/pre-commit-hooks/gorm-security-check.sh
language: script
files: '\.go$'
pass_filenames: false
stages: [manual] # Manual stage initially (soft launch)
verbose: true
description: "Detects GORM ID leaks and common GORM security mistakes"
- id: semgrep-scan
name: Semgrep Security Scan (Manual)
entry: scripts/pre-commit-hooks/semgrep-scan.sh
language: script
pass_filenames: false
verbose: true
stages: [manual] # Manual stage initially (reversible rollout)
- id: gitleaks-tuned-scan
name: Gitleaks Security Scan (Tuned, Manual)
entry: scripts/pre-commit-hooks/gitleaks-tuned-scan.sh
language: script
pass_filenames: false
verbose: true
stages: [manual] # Manual stage initially (reversible rollout)
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.47.0
hooks:
- id: markdownlint
args: ["--fix"]
exclude: '^(node_modules|\.venv|test-results|codeql-db|codeql-agent-results)/'
stages: [manual]

View File

@@ -1,2 +1,105 @@
.cache/
playwright/.auth/
# GHSA-69x3-g4r3-p962 / CVE-2026-25793: Nebula ECDSA Signature Malleability
# Severity: HIGH (CVSS 8.1) — Package: github.com/slackhq/nebula v1.9.7 in /usr/bin/caddy
# Fix exists in nebula v1.10.3, but smallstep/certificates (through v0.30.2) uses legacy nebula
# APIs removed in v1.10+, causing compile failures. Waiting on certificates upstream update.
# Charon does not use Nebula VPN PKI by default. Review by: 2026-05-10
# See also: .grype.yaml for full justification
# exp: 2026-05-10
CVE-2026-25793
# CVE-2026-27171: zlib CPU spin via crc32_combine64 infinite loop (DoS)
# Severity: MEDIUM (CVSS 5.5 NVD / 2.9 MITRE) — Package: zlib 1.3.1-r2 in Alpine base image
# Fix requires zlib >= 1.3.2. No upstream fix available: Alpine 3.23 still ships zlib 1.3.1-r2.
# Attack requires local access (AV:L); the vulnerable code path is not reachable via Charon's
# network-facing surface. Non-blocking by CI policy (MEDIUM). Review by: 2026-05-21
# exp: 2026-05-21
CVE-2026-27171
# CVE-2026-2673: OpenSSL TLS 1.3 server key exchange group downgrade (libcrypto3/libssl3)
# Severity: HIGH (CVSS 7.5) — Packages: libcrypto3 3.5.5-r0 and libssl3 3.5.5-r0 in Alpine base image
# No upstream fix available: Alpine 3.23 still ships libcrypto3/libssl3 3.5.5-r0 as of 2026-03-18.
# When DEFAULT is in TLS 1.3 group config, server may select a weaker key exchange group.
# Charon terminates TLS at the Caddy layer — the Go backend does not act as a raw TLS 1.3 server.
# Review by: 2026-05-18
# See also: .grype.yaml for full justification
# exp: 2026-05-18
CVE-2026-2673
# CVE-2026-33186 / GHSA-p77j-4mvh-x3m3: gRPC-Go authorization bypass via missing leading slash
# Severity: CRITICAL (CVSS 9.1) — Package: google.golang.org/grpc, embedded in CrowdSec (v1.74.2) and Caddy (v1.79.1)
# Fix exists at v1.79.3 — Charon's own dep is patched. Waiting on CrowdSec and Caddy upstream releases.
# CrowdSec's and Caddy's grpc servers are not exposed externally in a standard Charon deployment.
# Suppressed for CrowdSec/Caddy embedded binaries only — Charon's direct deps are fixed (v1.79.3).
# Review by: 2026-05-04
# See also: .grype.yaml for full justification
# exp: 2026-05-04
CVE-2026-33186
# GHSA-479m-364c-43vc: goxmldsig XML signature validation bypass (loop variable capture)
# Severity: HIGH (CVSS 7.5) — Package: github.com/russellhaering/goxmldsig v1.5.0, embedded in /usr/bin/caddy
# Fix exists at v1.6.0 — waiting on Caddy upstream (or caddy-security plugin) to release with patched goxmldsig.
# Charon does not configure SAML-based SSO by default; the vulnerable path is not reachable in a standard deployment.
# Awaiting Caddy upstream update to include goxmldsig v1.6.0.
# Review by: 2026-05-04
# See also: .grype.yaml for full justification
# exp: 2026-05-04
GHSA-479m-364c-43vc
# GHSA-6g7g-w4f8-9c9x: buger/jsonparser Delete panic on malformed JSON (DoS)
# Severity: HIGH (CVSS 7.5) — Package: github.com/buger/jsonparser v1.1.1, embedded in CrowdSec binaries
# No upstream fix available as of 2026-03-19 (issue #275 open, golang/vulndb #4514 open).
# Charon does not use this package; the vector requires reaching CrowdSec's internal processing pipeline.
# Review by: 2026-05-19
# See also: .grype.yaml for full justification
# exp: 2026-05-19
GHSA-6g7g-w4f8-9c9x
# GHSA-jqcq-xjh3-6g23: pgproto3/v2 DataRow.Decode panic on negative field length (DoS)
# Severity: HIGH (CVSS 7.5) — Package: github.com/jackc/pgproto3/v2 v2.3.3, embedded in CrowdSec binaries
# pgproto3/v2 is archived/EOL — no fix will be released. Fix path requires CrowdSec to migrate to pgx/v5.
# Charon uses SQLite; the PostgreSQL code path is not reachable in a standard deployment.
# Review by: 2026-05-19
# See also: .grype.yaml for full justification
# exp: 2026-05-19
GHSA-jqcq-xjh3-6g23
# GHSA-x6gf-mpr2-68h6 / CVE-2026-4427: pgproto3/v2 DataRow.Decode panic on negative field length (DoS)
# Severity: HIGH (CVSS 7.5) — Package: github.com/jackc/pgproto3/v2 v2.3.3, embedded in CrowdSec binaries
# NVD/Red Hat alias (CVE-2026-4427) for the same underlying bug as GHSA-jqcq-xjh3-6g23.
# pgproto3/v2 is archived/EOL — no fix will be released. Fix path requires CrowdSec to migrate to pgx/v5.
# Charon uses SQLite; the PostgreSQL code path is not reachable in a standard deployment.
# Review by: 2026-05-21
# See also: .grype.yaml for full justification
# exp: 2026-05-21
GHSA-x6gf-mpr2-68h6
# CVE-2026-32286: pgproto3/v2 buffer overflow in DataRow handling (DoS)
# Severity: HIGH (CVSS 7.5) — Package: github.com/jackc/pgproto3/v2 v2.3.3, embedded in CrowdSec binaries
# pgproto3/v2 v2.3.3 is the final release — repository archived Jul 12, 2025. No fix will be released.
# Fix exists only in pgproto3/v3 (used by pgx/v5). CrowdSec v1.7.7 (latest) still depends on pgx/v4 → pgproto3/v2.
# Dockerfile already applies best-effort mitigation (pgx/v4@v4.18.3).
# Charon uses SQLite; the PostgreSQL code path is not reachable in a standard deployment.
# Review by: 2026-07-09
# See also: .grype.yaml for full justification
# exp: 2026-07-09
CVE-2026-32286
# CVE-2026-33997 / GHSA-pxq6-2prw-chj9: Moby off-by-one error in plugin privilege validation
# Severity: MEDIUM (CVSS 6.8) — Package: github.com/docker/docker v28.5.2+incompatible
# Fixed in moby/moby v29.3.1 but no fix for docker/docker import path.
# Charon uses Docker client SDK only (list containers); plugin privilege validation is server-side.
# Review by: 2026-04-30
# See also: .grype.yaml for full justification
# exp: 2026-04-30
CVE-2026-33997
# GHSA-pxq6-2prw-chj9: Moby off-by-one error in plugin privilege validation (GHSA alias)
# Severity: MEDIUM (CVSS 6.8) — Package: github.com/docker/docker v28.5.2+incompatible
# GHSA alias for CVE-2026-33997. See CVE-2026-33997 entry above for full details.
# Review by: 2026-04-30
# See also: .grype.yaml for full justification
# exp: 2026-04-30
GHSA-pxq6-2prw-chj9

View File

@@ -1 +1 @@
v0.18.13
v0.27.0

8
.vscode/mcp.json vendored
View File

@@ -1,4 +1,5 @@
{
"inputs": [],
"servers": {
"microsoft/playwright-mcp": {
"type": "stdio",
@@ -8,11 +9,6 @@
],
"gallery": "https://api.mcp.github.com",
"version": "0.0.1-seed"
},
"gopls": {
"url": "http://localhost:8092",
"type": "sse"
}
},
"inputs": []
}
}

181
.vscode/tasks.json vendored
View File

@@ -371,9 +371,9 @@
}
},
{
"label": "Lint: Pre-commit (All Files)",
"label": "Lint: Lefthook Pre-commit (All Files)",
"type": "shell",
"command": ".github/skills/scripts/skill-runner.sh qa-precommit-all",
"command": "lefthook run pre-commit",
"group": "test",
"problemMatcher": []
},
@@ -454,7 +454,7 @@
{
"label": "Security: Trivy Scan",
"type": "shell",
"command": ".github/skills/scripts/skill-runner.sh security-scan-trivy",
"command": "TRIVY_DOCKER_RM=false .github/skills/scripts/skill-runner.sh security-scan-trivy",
"group": "test",
"problemMatcher": []
},
@@ -466,9 +466,9 @@
"problemMatcher": []
},
{
"label": "Security: Semgrep Scan (Manual Hook)",
"label": "Security: Semgrep Scan (Lefthook Pre-push)",
"type": "shell",
"command": "pre-commit run --hook-stage manual semgrep-scan --all-files",
"command": "lefthook run pre-push",
"group": "test",
"problemMatcher": []
},
@@ -480,9 +480,9 @@
"problemMatcher": []
},
{
"label": "Security: Gitleaks Scan (Tuned Manual Hook)",
"label": "Security: Gitleaks Scan (Lefthook Pre-push)",
"type": "shell",
"command": "pre-commit run --hook-stage manual gitleaks-tuned-scan --all-files",
"command": "lefthook run pre-push",
"group": "test",
"problemMatcher": []
},
@@ -501,14 +501,14 @@
{
"label": "Security: CodeQL Go Scan (DEPRECATED)",
"type": "shell",
"command": "codeql database create codeql-db-go --language=go --source-root=backend --overwrite && codeql database analyze codeql-db-go /projects/codeql/codeql/go/ql/src/codeql-suites/go-security-extended.qls --format=sarif-latest --output=codeql-results-go.sarif",
"command": "bash scripts/pre-commit-hooks/codeql-go-scan.sh",
"group": "test",
"problemMatcher": []
},
{
"label": "Security: CodeQL JS Scan (DEPRECATED)",
"type": "shell",
"command": "codeql database create codeql-db-js --language=javascript --source-root=frontend --overwrite && codeql database analyze codeql-db-js /projects/codeql/codeql/javascript/ql/src/codeql-suites/javascript-security-extended.qls --format=sarif-latest --output=codeql-results-js.sarif",
"command": "bash scripts/pre-commit-hooks/codeql-js-scan.sh",
"group": "test",
"problemMatcher": []
},
@@ -724,6 +724,13 @@
"group": "test",
"problemMatcher": []
},
{
"label": "Security: Caddy PR-1 Compatibility Matrix",
"type": "shell",
"command": "cd /projects/Charon && bash scripts/caddy-compat-matrix.sh --candidate-version 2.11.2 --patch-scenarios A,B,C --platforms linux/amd64,linux/arm64 --smoke-set boot_caddy,plugin_modules,config_validate,admin_api_health --output-dir test-results/caddy-compat --docs-report docs/reports/caddy-compatibility-matrix.md",
"group": "test",
"problemMatcher": []
},
{
"label": "Test: E2E Playwright (Skill)",
"type": "shell",
@@ -808,6 +815,162 @@
"close": false
}
},
{
"label": "Test: E2E Playwright (Chromium) - Non-Security Shards 1/4-4/4",
"type": "shell",
"command": "cd /projects/Charon && if [ -f .env ]; then set -a; . ./.env; set +a; fi && : \"${CHARON_EMERGENCY_TOKEN:?CHARON_EMERGENCY_TOKEN is required (set it in /projects/Charon/.env)}\" && CI=true PLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 CHARON_SECURITY_TESTS_ENABLED=false PLAYWRIGHT_SKIP_SECURITY_DEPS=1 TEST_WORKER_INDEX=1 npx playwright test --project=chromium --shard=1/4 --output=playwright-output/chromium-shard-1 tests/core tests/dns-provider-crud.spec.ts tests/dns-provider-types.spec.ts tests/integration tests/manual-dns-provider.spec.ts tests/monitoring tests/settings tests/tasks && cd /projects/Charon && CI=true PLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 CHARON_SECURITY_TESTS_ENABLED=false PLAYWRIGHT_SKIP_SECURITY_DEPS=1 TEST_WORKER_INDEX=2 npx playwright test --project=chromium --shard=2/4 --output=playwright-output/chromium-shard-2 tests/core tests/dns-provider-crud.spec.ts tests/dns-provider-types.spec.ts tests/integration tests/manual-dns-provider.spec.ts tests/monitoring tests/settings tests/tasks && cd /projects/Charon && CI=true PLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 CHARON_SECURITY_TESTS_ENABLED=false PLAYWRIGHT_SKIP_SECURITY_DEPS=1 TEST_WORKER_INDEX=3 npx playwright test --project=chromium --shard=3/4 --output=playwright-output/chromium-shard-3 tests/core tests/dns-provider-crud.spec.ts tests/dns-provider-types.spec.ts tests/integration tests/manual-dns-provider.spec.ts tests/monitoring tests/settings tests/tasks && cd /projects/Charon && CI=true PLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 CHARON_SECURITY_TESTS_ENABLED=false PLAYWRIGHT_SKIP_SECURITY_DEPS=1 TEST_WORKER_INDEX=4 npx playwright test --project=chromium --shard=4/4 --output=playwright-output/chromium-shard-4 tests/core tests/dns-provider-crud.spec.ts tests/dns-provider-types.spec.ts tests/integration tests/manual-dns-provider.spec.ts tests/monitoring tests/settings tests/tasks",
"group": "test",
"problemMatcher": [],
"presentation": {
"reveal": "always",
"panel": "dedicated",
"close": false
}
},
{
"label": "Test: E2E Playwright (Chromium) - Non-Security Shard 1/4",
"type": "shell",
"command": "cd /projects/Charon && if [ -f .env ]; then set -a; . ./.env; set +a; fi && : \"${CHARON_EMERGENCY_TOKEN:?CHARON_EMERGENCY_TOKEN is required (set it in /projects/Charon/.env)}\" && CI=true PLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 CHARON_SECURITY_TESTS_ENABLED=false PLAYWRIGHT_SKIP_SECURITY_DEPS=1 TEST_WORKER_INDEX=1 npx playwright test --project=chromium --shard=1/4 --output=playwright-output/chromium-shard-1 tests/core tests/dns-provider-crud.spec.ts tests/dns-provider-types.spec.ts tests/integration tests/manual-dns-provider.spec.ts tests/monitoring tests/settings tests/tasks",
"group": "test",
"problemMatcher": [],
"presentation": {
"reveal": "always",
"panel": "dedicated",
"close": false
}
},
{
"label": "Test: E2E Playwright (Chromium) - Non-Security Shard 2/4",
"type": "shell",
"command": "cd /projects/Charon && if [ -f .env ]; then set -a; . ./.env; set +a; fi && : \"${CHARON_EMERGENCY_TOKEN:?CHARON_EMERGENCY_TOKEN is required (set it in /projects/Charon/.env)}\" && CI=true PLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 CHARON_SECURITY_TESTS_ENABLED=false PLAYWRIGHT_SKIP_SECURITY_DEPS=1 TEST_WORKER_INDEX=2 npx playwright test --project=chromium --shard=2/4 --output=playwright-output/chromium-shard-2 tests/core tests/dns-provider-crud.spec.ts tests/dns-provider-types.spec.ts tests/integration tests/manual-dns-provider.spec.ts tests/monitoring tests/settings tests/tasks",
"group": "test",
"problemMatcher": [],
"presentation": {
"reveal": "always",
"panel": "dedicated",
"close": false
}
},
{
"label": "Test: E2E Playwright (Chromium) - Non-Security Shard 3/4",
"type": "shell",
"command": "cd /projects/Charon && if [ -f .env ]; then set -a; . ./.env; set +a; fi && : \"${CHARON_EMERGENCY_TOKEN:?CHARON_EMERGENCY_TOKEN is required (set it in /projects/Charon/.env)}\" && CI=true PLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 CHARON_SECURITY_TESTS_ENABLED=false PLAYWRIGHT_SKIP_SECURITY_DEPS=1 TEST_WORKER_INDEX=3 npx playwright test --project=chromium --shard=3/4 --output=playwright-output/chromium-shard-3 tests/core tests/dns-provider-crud.spec.ts tests/dns-provider-types.spec.ts tests/integration tests/manual-dns-provider.spec.ts tests/monitoring tests/settings tests/tasks",
"group": "test",
"problemMatcher": [],
"presentation": {
"reveal": "always",
"panel": "dedicated",
"close": false
}
},
{
"label": "Test: E2E Playwright (Chromium) - Non-Security Shard 4/4",
"type": "shell",
"command": "cd /projects/Charon && if [ -f .env ]; then set -a; . ./.env; set +a; fi && : \"${CHARON_EMERGENCY_TOKEN:?CHARON_EMERGENCY_TOKEN is required (set it in /projects/Charon/.env)}\" && CI=true PLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 CHARON_SECURITY_TESTS_ENABLED=false PLAYWRIGHT_SKIP_SECURITY_DEPS=1 TEST_WORKER_INDEX=4 npx playwright test --project=chromium --shard=4/4 --output=playwright-output/chromium-shard-4 tests/core tests/dns-provider-crud.spec.ts tests/dns-provider-types.spec.ts tests/integration tests/manual-dns-provider.spec.ts tests/monitoring tests/settings tests/tasks",
"group": "test",
"problemMatcher": [],
"presentation": {
"reveal": "always",
"panel": "dedicated",
"close": false
}
},
{
"label": "Test: E2E Playwright (WebKit) - Non-Security Shards 1/4-4/4",
"type": "shell",
"command": "cd /projects/Charon && if [ -f .env ]; then set -a; . ./.env; set +a; fi && : \"${CHARON_EMERGENCY_TOKEN:?CHARON_EMERGENCY_TOKEN is required (set it in /projects/Charon/.env)}\" && CI=true PLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 CHARON_SECURITY_TESTS_ENABLED=false PLAYWRIGHT_SKIP_SECURITY_DEPS=1 TEST_WORKER_INDEX=1 npx playwright test --project=webkit --shard=1/4 --output=playwright-output/webkit-shard-1 tests/core tests/dns-provider-crud.spec.ts tests/dns-provider-types.spec.ts tests/integration tests/manual-dns-provider.spec.ts tests/monitoring tests/settings tests/tasks && cd /projects/Charon && CI=true PLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 CHARON_SECURITY_TESTS_ENABLED=false PLAYWRIGHT_SKIP_SECURITY_DEPS=1 TEST_WORKER_INDEX=2 npx playwright test --project=webkit --shard=2/4 --output=playwright-output/webkit-shard-2 tests/core tests/dns-provider-crud.spec.ts tests/dns-provider-types.spec.ts tests/integration tests/manual-dns-provider.spec.ts tests/monitoring tests/settings tests/tasks && cd /projects/Charon && CI=true PLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 CHARON_SECURITY_TESTS_ENABLED=false PLAYWRIGHT_SKIP_SECURITY_DEPS=1 TEST_WORKER_INDEX=3 npx playwright test --project=webkit --shard=3/4 --output=playwright-output/webkit-shard-3 tests/core tests/dns-provider-crud.spec.ts tests/dns-provider-types.spec.ts tests/integration tests/manual-dns-provider.spec.ts tests/monitoring tests/settings tests/tasks && cd /projects/Charon && CI=true PLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 CHARON_SECURITY_TESTS_ENABLED=false PLAYWRIGHT_SKIP_SECURITY_DEPS=1 TEST_WORKER_INDEX=4 npx playwright test --project=webkit --shard=4/4 --output=playwright-output/webkit-shard-4 tests/core tests/dns-provider-crud.spec.ts tests/dns-provider-types.spec.ts tests/integration tests/manual-dns-provider.spec.ts tests/monitoring tests/settings tests/tasks",
"group": "test",
"problemMatcher": [],
"presentation": {
"reveal": "always",
"panel": "dedicated",
"close": false
}
},
{
"label": "Test: E2E Playwright (WebKit) - Non-Security Shard 1/4",
"type": "shell",
"command": "cd /projects/Charon && if [ -f .env ]; then set -a; . ./.env; set +a; fi && : \"${CHARON_EMERGENCY_TOKEN:?CHARON_EMERGENCY_TOKEN is required (set it in /projects/Charon/.env)}\" && CI=true PLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 CHARON_SECURITY_TESTS_ENABLED=false PLAYWRIGHT_SKIP_SECURITY_DEPS=1 TEST_WORKER_INDEX=1 npx playwright test --project=webkit --shard=1/4 --output=playwright-output/webkit-shard-1 tests/core tests/dns-provider-crud.spec.ts tests/dns-provider-types.spec.ts tests/integration tests/manual-dns-provider.spec.ts tests/monitoring tests/settings tests/tasks",
"group": "test",
"problemMatcher": [],
"presentation": {
"reveal": "always",
"panel": "dedicated",
"close": false
}
},
{
"label": "Test: E2E Playwright (WebKit) - Non-Security Shard 2/4",
"type": "shell",
"command": "cd /projects/Charon && if [ -f .env ]; then set -a; . ./.env; set +a; fi && : \"${CHARON_EMERGENCY_TOKEN:?CHARON_EMERGENCY_TOKEN is required (set it in /projects/Charon/.env)}\" && CI=true PLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 CHARON_SECURITY_TESTS_ENABLED=false PLAYWRIGHT_SKIP_SECURITY_DEPS=1 TEST_WORKER_INDEX=2 npx playwright test --project=webkit --shard=2/4 --output=playwright-output/webkit-shard-2 tests/core tests/dns-provider-crud.spec.ts tests/dns-provider-types.spec.ts tests/integration tests/manual-dns-provider.spec.ts tests/monitoring tests/settings tests/tasks",
"group": "test",
"problemMatcher": [],
"presentation": {
"reveal": "always",
"panel": "dedicated",
"close": false
}
},
{
"label": "Test: E2E Playwright (WebKit) - Non-Security Shard 3/4",
"type": "shell",
"command": "cd /projects/Charon && if [ -f .env ]; then set -a; . ./.env; set +a; fi && : \"${CHARON_EMERGENCY_TOKEN:?CHARON_EMERGENCY_TOKEN is required (set it in /projects/Charon/.env)}\" && CI=true PLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 CHARON_SECURITY_TESTS_ENABLED=false PLAYWRIGHT_SKIP_SECURITY_DEPS=1 TEST_WORKER_INDEX=3 npx playwright test --project=webkit --shard=3/4 --output=playwright-output/webkit-shard-3 tests/core tests/dns-provider-crud.spec.ts tests/dns-provider-types.spec.ts tests/integration tests/manual-dns-provider.spec.ts tests/monitoring tests/settings tests/tasks",
"group": "test",
"problemMatcher": [],
"presentation": {
"reveal": "always",
"panel": "dedicated",
"close": false
}
},
{
"label": "Test: E2E Playwright (WebKit) - Non-Security Shard 4/4",
"type": "shell",
"command": "cd /projects/Charon && if [ -f .env ]; then set -a; . ./.env; set +a; fi && : \"${CHARON_EMERGENCY_TOKEN:?CHARON_EMERGENCY_TOKEN is required (set it in /projects/Charon/.env)}\" && CI=true PLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 CHARON_SECURITY_TESTS_ENABLED=false PLAYWRIGHT_SKIP_SECURITY_DEPS=1 TEST_WORKER_INDEX=4 npx playwright test --project=webkit --shard=4/4 --output=playwright-output/webkit-shard-4 tests/core tests/dns-provider-crud.spec.ts tests/dns-provider-types.spec.ts tests/integration tests/manual-dns-provider.spec.ts tests/monitoring tests/settings tests/tasks",
"group": "test",
"problemMatcher": [],
"presentation": {
"reveal": "always",
"panel": "dedicated",
"close": false
}
},
{
"label": "Test: E2E Playwright (Chromium) - Security Suite",
"type": "shell",
"command": "cd /projects/Charon && if [ -f .env ]; then set -a; . ./.env; set +a; fi && : \"${CHARON_EMERGENCY_TOKEN:?CHARON_EMERGENCY_TOKEN is required (set it in /projects/Charon/.env)}\" && CI=true PLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 CHARON_SECURITY_TESTS_ENABLED=true PLAYWRIGHT_SKIP_SECURITY_DEPS=0 npx playwright test --project=security-tests --output=playwright-output/chromium-security tests/security",
"group": "test",
"problemMatcher": [],
"presentation": {
"reveal": "always",
"panel": "dedicated",
"close": false
}
},
{
"label": "Test: E2E Playwright (FireFox) - Security Suite",
"type": "shell",
"command": "cd /projects/Charon && if [ -f .env ]; then set -a; . ./.env; set +a; fi && : \"${CHARON_EMERGENCY_TOKEN:?CHARON_EMERGENCY_TOKEN is required (set it in /projects/Charon/.env)}\" && CI=true PLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 CHARON_SECURITY_TESTS_ENABLED=true PLAYWRIGHT_SKIP_SECURITY_DEPS=0 npx playwright test --project=firefox --output=playwright-output/firefox-security tests/security",
"group": "test",
"problemMatcher": [],
"presentation": {
"reveal": "always",
"panel": "dedicated",
"close": false
}
},
{
"label": "Test: E2E Playwright (WebKit) - Security Suite",
"type": "shell",
"command": "cd /projects/Charon && if [ -f .env ]; then set -a; . ./.env; set +a; fi && : \"${CHARON_EMERGENCY_TOKEN:?CHARON_EMERGENCY_TOKEN is required (set it in /projects/Charon/.env)}\" && CI=true PLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 CHARON_SECURITY_TESTS_ENABLED=true PLAYWRIGHT_SKIP_SECURITY_DEPS=0 npx playwright test --project=webkit --output=playwright-output/webkit-security tests/security",
"group": "test",
"problemMatcher": [],
"presentation": {
"reveal": "always",
"panel": "dedicated",
"close": false
}
},
{
"label": "Test: E2E Playwright with Coverage",
"type": "shell",

View File

@@ -126,11 +126,11 @@ graph TB
| **HTTP Framework** | Gin | Latest | Routing, middleware, HTTP handling |
| **Database** | SQLite | 3.x | Embedded database |
| **ORM** | GORM | Latest | Database abstraction layer |
| **Reverse Proxy** | Caddy Server | 2.11.0-beta.2 | Embedded HTTP/HTTPS proxy |
| **Reverse Proxy** | Caddy Server | 2.11.2 | Embedded HTTP/HTTPS proxy |
| **WebSocket** | gorilla/websocket | Latest | Real-time log streaming |
| **Crypto** | golang.org/x/crypto | Latest | Password hashing, encryption |
| **Metrics** | Prometheus Client | Latest | Application metrics |
| **Notifications** | Shoutrrr | Latest | Multi-platform alerts |
| **Notifications** | Notify (Discord-first) | Current | Discord notifications now; additional services in phased rollout |
| **Docker Client** | Docker SDK | Latest | Container discovery |
| **Logging** | Logrus + Lumberjack | Latest | Structured logging with rotation |
@@ -139,15 +139,15 @@ graph TB
| Component | Technology | Version | Purpose |
|-----------|-----------|---------|---------|
| **Framework** | React | 19.2.3 | UI framework |
| **Language** | TypeScript | 5.x | Type-safe JavaScript |
| **Build Tool** | Vite | 6.1.9 | Fast bundler and dev server |
| **CSS Framework** | Tailwind CSS | 3.x | Utility-first CSS |
| **Language** | TypeScript | 6.x | Type-safe JavaScript |
| **Build Tool** | Vite | 8.0.0-beta.18 | Fast bundler and dev server |
| **CSS Framework** | Tailwind CSS | 4.2.1 | Utility-first CSS |
| **Routing** | React Router | 7.x | Client-side routing |
| **HTTP Client** | Fetch API | Native | API communication |
| **State Management** | React Hooks + Context | Native | Global state |
| **Internationalization** | i18next | Latest | 5 language support |
| **Unit Testing** | Vitest | 2.x | Fast unit test runner |
| **E2E Testing** | Playwright | 1.50.x | Browser automation |
| **Unit Testing** | Vitest | 4.1.0-beta.6 | Fast unit test runner |
| **E2E Testing** | Playwright | 1.58.2 | Browser automation |
### Infrastructure
@@ -218,7 +218,7 @@ graph TB
│ │ └── main.tsx # Application entry point
│ ├── public/ # Static assets
│ ├── package.json # NPM dependencies
│ └── vite.config.js # Vite configuration
│ └── vite.config.ts # Vite configuration
├── .docker/ # Docker configuration
│ ├── compose/ # Docker Compose files
@@ -306,11 +306,13 @@ graph TB
**Key Modules:**
#### API Layer (`internal/api/`)
- **Handlers:** Process HTTP requests, validate input, return responses
- **Middleware:** CORS, GZIP, authentication, logging, metrics, panic recovery
- **Routes:** Route registration and grouping (public vs authenticated)
**Example Endpoints:**
- `GET /api/v1/proxy-hosts` - List all proxy hosts
- `POST /api/v1/proxy-hosts` - Create new proxy host
- `PUT /api/v1/proxy-hosts/:id` - Update proxy host
@@ -318,6 +320,7 @@ graph TB
- `WS /api/v1/logs` - WebSocket for real-time logs
#### Service Layer (`internal/services/`)
- **ProxyService:** CRUD operations for proxy hosts, validation logic
- **CertificateService:** ACME certificate provisioning and renewal
- **DockerService:** Container discovery and monitoring
@@ -327,12 +330,14 @@ graph TB
**Design Pattern:** Services contain business logic and call multiple repositories/managers
#### Caddy Manager (`internal/caddy/`)
- **Manager:** Orchestrates Caddy configuration updates
- **Config Builder:** Generates Caddy JSON from database models
- **Reload Logic:** Atomic config application with rollback on failure
- **Security Integration:** Injects Cerberus middleware into Caddy pipelines
**Responsibilities:**
1. Generate Caddy JSON configuration from database state
2. Validate configuration before applying
3. Trigger Caddy reload via JSON API
@@ -340,22 +345,26 @@ graph TB
5. Integrate security layers (WAF, ACL, Rate Limiting)
#### Security Suite (`internal/cerberus/`)
- **ACL (Access Control Lists):** IP-based allow/deny rules, GeoIP blocking
- **WAF (Web Application Firewall):** Coraza engine with OWASP CRS
- **CrowdSec:** Behavior-based threat detection with global intelligence
- **Rate Limiter:** Per-IP request throttling
**Integration Points:**
- Middleware injection into Caddy request pipeline
- Database-driven rule configuration
- Metrics collection for security events
#### Database Layer (`internal/database/`)
- **Migrations:** Automatic schema versioning with GORM AutoMigrate
- **Seeding:** Default settings and admin user creation
- **Connection Management:** SQLite with WAL mode and connection pooling
**Schema Overview:**
- **ProxyHost:** Domain, upstream target, SSL config
- **RemoteServer:** Upstream server definitions
- **CaddyConfig:** Generated Caddy configuration (audit trail)
@@ -372,6 +381,7 @@ graph TB
**Component Architecture:**
#### Pages (`src/pages/`)
- **Dashboard:** System overview, recent activity, quick actions
- **ProxyHosts:** List, create, edit, delete proxy configurations
- **Certificates:** Manage SSL/TLS certificates, view expiry
@@ -380,17 +390,20 @@ graph TB
- **Users:** User management (admin only)
#### Components (`src/components/`)
- **Forms:** Reusable form inputs with validation
- **Modals:** Dialog components for CRUD operations
- **Tables:** Data tables with sorting, filtering, pagination
- **Layout:** Header, sidebar, navigation
#### API Client (`src/api/`)
- Centralized API calls with error handling
- Request/response type definitions
- Authentication token management
**Example:**
```typescript
export const getProxyHosts = async (): Promise<ProxyHost[]> => {
const response = await fetch('/api/v1/proxy-hosts', {
@@ -402,11 +415,13 @@ export const getProxyHosts = async (): Promise<ProxyHost[]> => {
```
#### State Management
- **React Context:** Global state for auth, theme, language
- **Local State:** Component-specific state with `useState`
- **Custom Hooks:** Encapsulate API calls and side effects
**Example Hook:**
```typescript
export const useProxyHosts = () => {
const [hosts, setHosts] = useState<ProxyHost[]>([]);
@@ -425,11 +440,13 @@ export const useProxyHosts = () => {
**Purpose:** High-performance reverse proxy with automatic HTTPS
**Integration:**
- Embedded as a library in the Go backend
- Configured via JSON API (not Caddyfile)
- Listens on ports 80 (HTTP) and 443 (HTTPS)
**Features Used:**
- Dynamic configuration updates without restarts
- Automatic HTTPS with Let's Encrypt and ZeroSSL
- DNS challenge support for wildcard certificates
@@ -437,6 +454,7 @@ export const useProxyHosts = () => {
- Request logging and metrics
**Configuration Flow:**
1. User creates proxy host via frontend
2. Backend validates and saves to database
3. Caddy Manager generates JSON configuration
@@ -461,12 +479,14 @@ For each proxy host, Charon generates **two routes** with the same domain:
- Handlers: Full Cerberus security suite
This pattern is **intentional and valid**:
- Emergency route provides break-glass access to security controls
- Main route protects application with enterprise security features
- Caddy processes routes in order (emergency matches first)
- Validator allows duplicate hosts when one has paths and one doesn't
**Example:**
```json
// Emergency Route (evaluated first)
{
@@ -488,6 +508,7 @@ This pattern is **intentional and valid**:
**Purpose:** Persistent data storage
**Why SQLite:**
- Embedded (no external database server)
- Serverless (perfect for single-user/small team)
- ACID compliant with WAL mode
@@ -495,16 +516,19 @@ This pattern is **intentional and valid**:
- Backup-friendly (single file)
**Configuration:**
- **WAL Mode:** Allows concurrent reads during writes
- **Foreign Keys:** Enforced referential integrity
- **Pragma Settings:** Performance optimizations
**Backup Strategy:**
- Automated daily backups to `data/backups/`
- Retention: 7 daily, 4 weekly, 12 monthly backups
- Backup during low-traffic periods
**Migrations:**
- GORM AutoMigrate for schema changes
- Manual migrations for complex data transformations
- Rollback support via backup restoration
@@ -537,6 +561,7 @@ graph LR
**Purpose:** Prevent brute-force attacks and API abuse
**Implementation:**
- Per-IP request counters with sliding window
- Configurable thresholds (e.g., 100 req/min, 1000 req/hour)
- HTTP 429 response when limit exceeded
@@ -547,12 +572,15 @@ graph LR
**Purpose:** Behavior-based threat detection
**Features:**
- Local log analysis (brute-force, port scans, exploits)
- Global threat intelligence (crowd-sourced IP reputation)
- Automatic IP banning with configurable duration
- Decision management API (view, create, delete bans)
- IP whitelist management: operators add/remove IPs and CIDRs via the management UI; entries are persisted in SQLite and regenerated into a `crowdsecurity/whitelists` parser YAML on every mutating operation and at startup
**Modes:**
- **Local Only:** No external API calls
- **API Mode:** Sync with CrowdSec cloud for global intelligence
@@ -561,12 +589,14 @@ graph LR
**Purpose:** IP-based access control
**Features:**
- Per-proxy-host allow/deny rules
- CIDR range support (e.g., `192.168.1.0/24`)
- Geographic blocking via GeoIP2 (MaxMind)
- Admin whitelist (emergency access)
**Evaluation Order:**
1. Check admin whitelist (always allow)
2. Check deny list (explicit block)
3. Check allow list (explicit allow)
@@ -579,6 +609,7 @@ graph LR
**Engine:** Coraza with OWASP Core Rule Set (CRS)
**Detection Categories:**
- SQL Injection (SQLi)
- Cross-Site Scripting (XSS)
- Remote Code Execution (RCE)
@@ -587,12 +618,14 @@ graph LR
- Command Injection
**Modes:**
- **Monitor:** Log but don't block (testing)
- **Block:** Return HTTP 403 for violations
### Layer 5: Application Security
**Additional Protections:**
- **SSRF Prevention:** Block requests to private IP ranges in webhooks/URL validation
- **HTTP Security Headers:** CSP, HSTS, X-Frame-Options, X-Content-Type-Options
- **Input Validation:** Server-side validation for all user inputs
@@ -610,6 +643,7 @@ graph LR
3. **Direct Database Access:** Manual SQLite update as last resort
**Emergency Token:**
- 64-character hex token set via `CHARON_EMERGENCY_TOKEN`
- Grants temporary admin access
- Rotated after each use
@@ -635,6 +669,7 @@ Charon operates with **two distinct traffic flows** on separate ports, each with
- **Testing:** Playwright E2E tests verify UI/UX functionality on this port
**Why No Middleware?**
- Management interface must remain accessible even when security modules are misconfigured
- Emergency endpoints (`/api/v1/emergency/*`) require unrestricted access for system recovery
- Separation of concerns: admin access control is handled by JWT, not proxy-level security
@@ -797,6 +832,7 @@ sequenceDiagram
**Rationale:** Simplicity over scalability - target audience is home users and small teams
**Container Contents:**
- Frontend static files (Vite build output)
- Go backend binary
- Embedded Caddy server
@@ -911,11 +947,13 @@ services:
### High Availability Considerations
**Current Limitations:**
- SQLite does not support clustering
- Single point of failure (one container)
- Not designed for horizontal scaling
**Future Options:**
- PostgreSQL backend for HA deployments
- Read replicas for load balancing
- Container orchestration (Kubernetes, Docker Swarm)
@@ -927,6 +965,7 @@ services:
### Local Development Setup
1. **Prerequisites:**
```bash
- Go 1.26+ (backend development)
- Node.js 23+ and npm (frontend development)
@@ -935,12 +974,14 @@ services:
```
2. **Clone Repository:**
```bash
git clone https://github.com/Wikid82/Charon.git
cd Charon
```
3. **Backend Development:**
```bash
cd backend
go mod download
@@ -949,6 +990,7 @@ services:
```
4. **Frontend Development:**
```bash
cd frontend
npm install
@@ -957,6 +999,7 @@ services:
```
5. **Full-Stack Development (Docker):**
```bash
docker-compose -f .docker/compose/docker-compose.dev.yml up
# Frontend + Backend + Caddy in one container
@@ -965,12 +1008,14 @@ services:
### Git Workflow
**Branch Strategy:**
- `main`: Stable production branch
- `feature/*`: New feature development
- `fix/*`: Bug fixes
- `chore/*`: Maintenance tasks
**Commit Convention:**
- `feat:` New user-facing feature
- `fix:` Bug fix in application code
- `chore:` Infrastructure, CI/CD, dependencies
@@ -979,6 +1024,7 @@ services:
- `test:` Adding or updating tests
**Example:**
```
feat: add DNS-01 challenge support for Cloudflare
@@ -1031,6 +1077,7 @@ Closes #123
**Purpose:** Validate critical user flows in a real browser
**Scope:**
- User authentication
- Proxy host CRUD operations
- Certificate provisioning
@@ -1038,6 +1085,7 @@ Closes #123
- Real-time log streaming
**Execution:**
```bash
# Run against Docker container
npx playwright test --project=chromium
@@ -1050,10 +1098,12 @@ npx playwright test --debug
```
**Coverage Modes:**
- **Docker Mode:** Integration testing, no coverage (0% reported)
- **Vite Dev Mode:** Coverage collection with V8 inspector
**Why Two Modes?**
- Playwright coverage requires source maps and raw source files
- Docker serves pre-built production files (no source maps)
- Vite dev server exposes source files for coverage instrumentation
@@ -1067,6 +1117,7 @@ npx playwright test --debug
**Coverage Target:** 85% minimum
**Execution:**
```bash
# Run all tests
go test ./...
@@ -1079,11 +1130,13 @@ go test -cover ./...
```
**Test Organization:**
- `*_test.go` files alongside source code
- Table-driven tests for comprehensive coverage
- Mocks for external dependencies (database, HTTP clients)
**Example:**
```go
func TestCreateProxyHost(t *testing.T) {
tests := []struct {
@@ -1123,6 +1176,7 @@ func TestCreateProxyHost(t *testing.T) {
**Coverage Target:** 85% minimum
**Execution:**
```bash
# Run all tests
npm test
@@ -1135,6 +1189,7 @@ npm run test:coverage
```
**Test Organization:**
- `*.test.tsx` files alongside components
- Mock API calls with MSW (Mock Service Worker)
- Snapshot tests for UI consistency
@@ -1146,12 +1201,14 @@ npm run test:coverage
**Location:** `backend/integration/`
**Scope:**
- API endpoint end-to-end flows
- Database migrations
- Caddy manager integration
- CrowdSec API calls
**Execution:**
```bash
go test ./integration/...
```
@@ -1161,6 +1218,7 @@ go test ./integration/...
**Automated Hooks (via `.pre-commit-config.yaml`):**
**Fast Stage (< 5 seconds):**
- Trailing whitespace removal
- EOF fixer
- YAML syntax check
@@ -1168,11 +1226,13 @@ go test ./integration/...
- Markdown link validation
**Manual Stage (run explicitly):**
- Backend coverage tests (60-90s)
- Frontend coverage tests (30-60s)
- TypeScript type checking (10-20s)
**Why Manual?**
- Coverage tests are slow and would block commits
- Developers run them on-demand before pushing
- CI enforces coverage on pull requests
@@ -1180,10 +1240,12 @@ go test ./integration/...
### Continuous Integration (GitHub Actions)
**Workflow Triggers:**
- `push` to `main`, `feature/*`, `fix/*`
- `pull_request` to `main`
**CI Jobs:**
1. **Lint:** golangci-lint, ESLint, markdownlint, hadolint
2. **Test:** Go tests, Vitest, Playwright
3. **Security:** Trivy, CodeQL, Grype, Govulncheck
@@ -1205,6 +1267,7 @@ go test ./integration/...
- **PRERELEASE:** `-beta.1`, `-rc.1`, etc.
**Examples:**
- `1.0.0` - Stable release
- `1.1.0` - New feature (DNS provider support)
- `1.1.1` - Bug fix (GORM query fix)
@@ -1215,12 +1278,14 @@ go test ./integration/...
### Build Pipeline (Multi-Platform)
**Platforms Supported:**
- `linux/amd64`
- `linux/arm64`
**Build Process:**
1. **Frontend Build:**
```bash
cd frontend
npm ci --only=production
@@ -1229,6 +1294,7 @@ go test ./integration/...
```
2. **Backend Build:**
```bash
cd backend
go build -o charon cmd/api/main.go
@@ -1236,6 +1302,7 @@ go test ./integration/...
```
3. **Docker Image Build:**
```bash
docker buildx build \
--platform linux/amd64,linux/arm64 \
@@ -1259,6 +1326,14 @@ go test ./integration/...
9. **Release Notes:** Generate changelog from commits
10. **Notify:** Send release notification (Discord, email)
**Mandatory rollout gates (sign-off block):**
1. Digest freshness and index digest parity across GHCR and Docker Hub
2. Per-arch digest parity across GHCR and Docker Hub
3. SBOM and vulnerability scans against immutable refs (`image@sha256:...`)
4. Artifact freshness timestamps after push
5. Evidence block with required rollout verification fields
### Supply Chain Security
**Components:**
@@ -1284,6 +1359,7 @@ go test ./integration/...
- Level: SLSA Build L3 (hermetic builds)
**Verification Example:**
```bash
# Verify image signature
cosign verify \
@@ -1292,15 +1368,16 @@ cosign verify \
wikid82/charon:latest
# Inspect SBOM
syft wikid82/charon:latest -o json
syft ghcr.io/wikid82/charon@sha256:<index-digest> -o json
# Scan for vulnerabilities
grype wikid82/charon:latest
grype ghcr.io/wikid82/charon@sha256:<index-digest>
```
### Rollback Strategy
**Container Rollback:**
```bash
# List available versions
docker images wikid82/charon
@@ -1311,6 +1388,7 @@ docker-compose up -d --pull always wikid82/charon:1.1.1
```
**Database Rollback:**
```bash
# Restore from backup
docker exec charon /app/scripts/restore-backup.sh \
@@ -1333,8 +1411,8 @@ docker exec charon /app/scripts/restore-backup.sh \
- Future: Dynamic plugin loading for custom providers
2. **Notification Channels:**
- Shoutrrr provides 40+ channels (Discord, Slack, Email, etc.)
- Custom channels via Shoutrrr service URLs
- Current rollout is Discord-only for notifications
- Additional services are enabled later in validated phases
3. **Authentication Providers:**
- Current: Local database authentication
@@ -1347,11 +1425,13 @@ docker exec charon /app/scripts/restore-backup.sh \
### API Extensibility
**REST API Design:**
- Version prefix: `/api/v1/`
- Future versions: `/api/v2/` (backward-compatible)
- Deprecation policy: 2 major versions supported
**WebHooks (Future):**
- Event notifications for external systems
- Triggers: Proxy host created, certificate renewed, security event
- Payload: JSON with event type and data
@@ -1361,6 +1441,7 @@ docker exec charon /app/scripts/restore-backup.sh \
**Current:** Cerberus security middleware injected into Caddy pipeline
**Future:**
- User-defined middleware (rate limiting rules, custom headers)
- JavaScript/Lua scripting for request transformation
- Plugin marketplace for community contributions
@@ -1444,6 +1525,7 @@ docker exec charon /app/scripts/restore-backup.sh \
**GitHub Copilot Instructions:**
All agents (`Planning`, `Backend_Dev`, `Frontend_Dev`, `DevOps`) must reference `ARCHITECTURE.md` when:
- Creating new components
- Modifying core systems
- Changing integration points

View File

@@ -7,17 +7,55 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- **CrowdSec Dashboard**: Visual analytics for CrowdSec security data within the Security section
- Summary cards showing total bans, active bans, unique IPs, and top scenario
- Interactive charts: ban timeline (area), top attacking IPs (bar), scenario breakdown (pie)
- Configurable time range selector (1h, 6h, 24h, 7d, 30d)
- Active decisions table with IP, scenario, duration, type, and time remaining
- Alerts feed with pagination sourced from CrowdSec LAPI
- CSV and JSON export for decisions data
- Server-side caching (3060s TTL) for fast dashboard loads
- Full i18n support across all 5 locales (en, de, fr, es, zh)
- Keyboard navigable, screen-reader compatible (WCAG 2.2 AA)
- **Notifications:** Added Ntfy notification provider with support for self-hosted and cloud instances, optional Bearer token authentication, and JSON template customization
- **Certificate Deletion**: Clean up expired and unused certificates directly from the Certificates page
- Expired Let's Encrypt certificates not attached to any proxy host can now be deleted
- Custom and staging certificates remain deletable when not in use
- In-use certificates show a disabled delete button with a tooltip explaining why
- Native browser confirmation replaced with an accessible, themed confirmation dialog
- **Pushover Notification Provider**: Send push notifications to your devices via the Pushover app
- Supports JSON templates (minimal, detailed, custom)
- Application API Token stored securely — never exposed in API responses
- User Key stored in the URL field, following the same pattern as Telegram
- Feature flag: `feature.notifications.service.pushover.enabled` (on by default)
- Emergency priority (2) is intentionally unsupported — deferred to a future release
- **Slack Notification Provider**: Send alerts to Slack channels via Incoming Webhooks
- Supports JSON templates (minimal, detailed, custom) with Slack's native `text` format
- Webhook URL stored securely — never exposed in API responses
- Optional channel display name for easy identification in provider list
- Feature flag: `feature.notifications.service.slack.enabled` (on by default)
- See [Notification Guide](docs/features/notifications.md) for setup instructions
### CI/CD
- **Supply Chain**: Optimized verification workflow to prevent redundant builds
- Change: Removed direct Push/PR triggers; now waits for 'Docker Build' via `workflow_run`
### Security
- **Supply Chain**: Enhanced PR verification workflow stability and accuracy
- **Vulnerability Reporting**: Eliminated false negatives ("0 vulnerabilities") by enforcing strict failure conditions
- **Tooling**: Switched to manual Grype installation ensuring usage of latest stable binary
- **Observability**: Improved debugging visibility for vulnerability scans and SARIF generation
### Performance
- **E2E Tests**: Reduced feature flag API calls by 90% through conditional polling optimization (Phase 2)
- Conditional skip: Exits immediately if flags already in expected state (~50% of cases)
- Request coalescing: Shares in-flight API requests between parallel test workers
@@ -29,8 +67,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Prevents timeout errors in Firefox/WebKit caused by strict label matching
### Fixed
- **Notifications:** Fixed Pushover token-clearing bug where tokens were silently stripped on provider create/update
- **TCP Monitor Creation**: Fixed misleading form UX that caused silent HTTP 500 errors when creating TCP monitors
- Corrected URL placeholder to show `host:port` format instead of the incorrect `tcp://host:port` prefix
- Added dynamic per-type placeholder and helper text (HTTP monitors show a full URL example; TCP monitors show `host:port`)
- Added client-side validation that blocks form submission when a scheme prefix (e.g. `tcp://`) is detected, with an inline error message
- Reordered form fields so the monitor type selector appears above the URL input, making the dynamic helper text immediately relevant
- i18n: Added 5 new translation keys across en, de, fr, es, and zh locales
- **CI: Rate Limit Integration Tests**: Hardened test script reliability — login now validates HTTP status, Caddy admin API readiness gated on `/config/` poll, security config failures are fatal with full diagnostics, and poll interval increased to 5s
- **CI: Rate Limit Integration Tests**: Removed stale GeoIP database SHA256 checksum from Dockerfile non-CI path (hash was perpetually stale due to weekly upstream updates)
- **CI: Rate Limit Integration Tests**: Fixed Caddy admin API debug dump URL to use canonical trailing slash in workflow
- Fixed: Added robust validation and debug logging for Docker image tags to prevent invalid reference errors.
- Fixed: Removed log masking for image references and added manifest validation to debug CI failures.
- **Proxy Hosts**: Fixed ACL and Security Headers dropdown selections so create/edit saves now keep the selected values (including clearing to none) after submit and reload.
- **CI**: Fixed Docker image reference output so integration jobs never pull an empty image ref
- **E2E Test Reliability**: Resolved test timeout issues affecting CI/CD pipeline stability
- Fixed config reload overlay blocking test interactions
@@ -40,6 +90,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Test Performance**: Reduced system settings test execution time by 31% (from 23 minutes to 16 minutes)
### Changed
- **Testing Infrastructure**: Enhanced E2E test helpers with better synchronization and error handling
- **CI**: Optimized E2E workflow shards [Reduced from 4 to 3]

View File

@@ -33,7 +33,17 @@ This project follows a Code of Conduct that all contributors are expected to adh
### Development Tools
Install golangci-lint for pre-commit hooks (required for Go development):
Install golangci-lint for lefthook pre-commit-phase hooks (required for Go development):
Also install lefthook itself so the git hooks work:
```bash
# Option 1: Homebrew (macOS/Linux)
brew install lefthook
# Option 2: Go install
go install github.com/evilmartians/lefthook@latest
```
```bash
# Option 1: Homebrew (macOS/Linux)
@@ -59,7 +69,7 @@ golangci-lint --version
# Should output: golangci-lint has version 1.xx.x ...
```
**Note:** Pre-commit hooks will **BLOCK commits** if golangci-lint finds issues. This is intentional - fix the issues before committing.
**Note:** Lefthook pre-commit-phase hooks will **BLOCK commits** if golangci-lint finds issues. This is intentional - fix the issues before committing.
### CI/CD Go Version Management
@@ -72,19 +82,22 @@ For local development, install go 1.26.0+ from [go.dev/dl](https://go.dev/dl/).
When the project's Go version is updated (usually by Renovate):
1. **Pull the latest changes**
```bash
git pull
```
2. **Update your local Go installation**
```bash
# Run the Go update skill (downloads and installs the new version)
.github/skills/scripts/skill-runner.sh utility-update-go-version
```
3. **Rebuild your development tools**
```bash
# This fixes pre-commit hook errors and IDE issues
# This fixes lefthook hook errors and IDE issues
./scripts/rebuild-go-tools.sh
```
@@ -104,7 +117,7 @@ Rebuilding tools with `./scripts/rebuild-go-tools.sh` fixes this by compiling th
**What if I forget?**
Don't worry! The pre-commit hook will detect the version mismatch and automatically rebuild tools for you. You'll see:
Don't worry! The lefthook pre-commit hook will detect the version mismatch and automatically rebuild tools for you. You'll see:
```
⚠️ golangci-lint Go version mismatch:

View File

@@ -8,21 +8,49 @@ ARG VCS_REF
# Set BUILD_DEBUG=1 to build with debug symbols (required for Delve debugging)
ARG BUILD_DEBUG=0
# ---- Pinned Toolchain Versions ----
# renovate: datasource=docker depName=golang versioning=docker
ARG GO_VERSION=1.26.2
# renovate: datasource=docker depName=alpine versioning=docker
ARG ALPINE_IMAGE=alpine:3.23.4@sha256:5b10f432ef3da1b8d4c7eb6c487f2f5a8f096bc91145e68878dd4a5019afde11
# ---- Shared CrowdSec Version ----
# renovate: datasource=github-releases depName=crowdsecurity/crowdsec
ARG CROWDSEC_VERSION=1.7.7
# CrowdSec fallback tarball checksum (v${CROWDSEC_VERSION})
ARG CROWDSEC_RELEASE_SHA256=704e37121e7ac215991441cef0d8732e33fa3b1a2b2b88b53a0bfe5e38f863bd
# ---- Shared Go Security Patches ----
# renovate: datasource=go depName=github.com/expr-lang/expr
ARG EXPR_LANG_VERSION=1.17.8
# renovate: datasource=go depName=golang.org/x/net
ARG XNET_VERSION=0.53.0
# renovate: datasource=go depName=github.com/smallstep/certificates
ARG SMALLSTEP_CERTIFICATES_VERSION=0.30.0
# renovate: datasource=npm depName=npm
ARG NPM_VERSION=11.11.1
# Allow pinning Caddy version - Renovate will update this
# Build the most recent Caddy 2.x release (keeps major pinned under v3).
# Setting this to '2' tells xcaddy to resolve the latest v2.x tag so we
# avoid accidentally pulling a v3 major release. Renovate can still update
# this ARG to a specific v2.x tag when desired.
## Try to build the requested Caddy v2.x tag (Renovate can update this ARG).
## If the requested tag isn't available, fall back to a known-good v2.11.0-beta.2 build.
ARG CADDY_VERSION=2.11.0-beta.2
## If the requested tag isn't available, fall back to a known-good v2.11.2 build.
ARG CADDY_VERSION=2.11.2
ARG CADDY_CANDIDATE_VERSION=2.11.2
ARG CADDY_USE_CANDIDATE=0
ARG CADDY_PATCH_SCENARIO=B
# renovate: datasource=go depName=github.com/greenpau/caddy-security
ARG CADDY_SECURITY_VERSION=1.1.62
# renovate: datasource=go depName=github.com/corazawaf/coraza-caddy
ARG CORAZA_CADDY_VERSION=2.5.0
## When an official caddy image tag isn't available on the host, use a
## plain Alpine base image and overwrite its caddy binary with our
## xcaddy-built binary in the later COPY step. This avoids relying on
## upstream caddy image tags while still shipping a pinned caddy binary.
## Alpine 3.23 base to reduce glibc CVE exposure and image size.
# renovate: datasource=docker depName=alpine versioning=docker
ARG CADDY_IMAGE=alpine:3.23.3
# ---- Cross-Compilation Helpers ----
# renovate: datasource=docker depName=tonistiigi/xx
@@ -33,8 +61,7 @@ FROM --platform=$BUILDPLATFORM tonistiigi/xx:1.9.0@sha256:c64defb9ed5a91eacb37f9
# This fixes 22 HIGH/CRITICAL CVEs in stdlib embedded in Debian's gosu package
# CVEs fixed: CVE-2023-24531, CVE-2023-24540, CVE-2023-29402, CVE-2023-29404,
# CVE-2023-29405, CVE-2024-24790, CVE-2025-22871, and 15 more
# renovate: datasource=docker depName=golang
FROM --platform=$BUILDPLATFORM golang:1.26-alpine AS gosu-builder
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS gosu-builder
COPY --from=xx / /
WORKDIR /tmp/gosu
@@ -65,7 +92,7 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
# ---- Frontend Builder ----
# Build the frontend using the BUILDPLATFORM to avoid arm64 musl Rollup native issues
# renovate: datasource=docker depName=node
FROM --platform=$BUILDPLATFORM node:24.13.1-alpine AS frontend-builder
FROM --platform=$BUILDPLATFORM node:24.15.0-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f AS frontend-builder
WORKDIR /app/frontend
# Copy frontend package files
@@ -76,9 +103,12 @@ ARG VERSION=dev
# Make version available to Vite as VITE_APP_VERSION during the frontend build
ENV VITE_APP_VERSION=${VERSION}
# Set environment to bypass native binary requirement for cross-arch builds
ENV npm_config_rollup_skip_nodejs_native=1 \
ROLLUP_SKIP_NODEJS_NATIVE=1
# Vite 8: Rolldown native bindings auto-resolved per platform via optionalDependencies
ARG NPM_VERSION
# hadolint ignore=DL3017
RUN apk upgrade --no-cache && \
npm install -g npm@${NPM_VERSION} --no-fund --no-audit && \
npm cache clean --force
RUN npm ci
@@ -88,8 +118,7 @@ RUN --mount=type=cache,target=/app/frontend/node_modules/.cache \
npm run build
# ---- Backend Builder ----
# renovate: datasource=docker depName=golang
FROM --platform=$BUILDPLATFORM golang:1.26-alpine AS backend-builder
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS backend-builder
# Copy xx helpers for cross-compilation
COPY --from=xx / /
@@ -102,7 +131,7 @@ SHELL ["/bin/ash", "-o", "pipefail", "-c"]
ARG TARGETPLATFORM
ARG TARGETARCH
# hadolint ignore=DL3018
RUN apk add --no-cache clang lld
RUN apk add --no-cache git clang lld
# hadolint ignore=DL3059
# hadolint ignore=DL3018
# Install musl (headers + runtime) and gcc for cross-compilation linker
@@ -131,7 +160,7 @@ RUN set -eux; \
# Note: xx-go install puts binaries in /go/bin/TARGETOS_TARGETARCH/dlv if cross-compiling.
# We find it and move it to /go/bin/dlv so it's in a consistent location for the next stage.
# renovate: datasource=go depName=github.com/go-delve/delve
ARG DLV_VERSION=1.26.0
ARG DLV_VERSION=1.26.2
# hadolint ignore=DL3059,DL4006
RUN CGO_ENABLED=0 xx-go install github.com/go-delve/delve/cmd/dlv@v${DLV_VERSION} && \
DLV_PATH=$(find /go/bin -name dlv -type f | head -n 1) && \
@@ -191,16 +220,23 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
# ---- Caddy Builder ----
# Build Caddy from source to ensure we use the latest Go version and dependencies
# This fixes vulnerabilities found in the pre-built Caddy images (e.g. CVE-2025-59530, stdlib issues)
# renovate: datasource=docker depName=golang
FROM --platform=$BUILDPLATFORM golang:1.26-alpine AS caddy-builder
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS caddy-builder
ARG TARGETOS
ARG TARGETARCH
ARG CADDY_VERSION
ARG CADDY_CANDIDATE_VERSION
ARG CADDY_USE_CANDIDATE
ARG CADDY_PATCH_SCENARIO
ARG CADDY_SECURITY_VERSION
ARG CORAZA_CADDY_VERSION
# renovate: datasource=go depName=github.com/caddyserver/xcaddy
ARG XCADDY_VERSION=0.4.5
ARG EXPR_LANG_VERSION
ARG XNET_VERSION
ARG SMALLSTEP_CERTIFICATES_VERSION
# hadolint ignore=DL3018
RUN apk add --no-cache git
RUN apk add --no-cache bash git
# hadolint ignore=DL3062
RUN --mount=type=cache,target=/go/pkg/mod \
go install github.com/caddyserver/xcaddy/cmd/xcaddy@v${XCADDY_VERSION}
@@ -212,13 +248,20 @@ RUN --mount=type=cache,target=/go/pkg/mod \
# hadolint ignore=SC2016
RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg/mod \
sh -c 'set -e; \
bash -c 'set -e; \
CADDY_TARGET_VERSION="${CADDY_VERSION}"; \
if [ "${CADDY_USE_CANDIDATE}" = "1" ]; then \
CADDY_TARGET_VERSION="${CADDY_CANDIDATE_VERSION}"; \
fi; \
echo "Using Caddy target version: v${CADDY_TARGET_VERSION}"; \
echo "Using Caddy patch scenario: ${CADDY_PATCH_SCENARIO}"; \
export XCADDY_SKIP_CLEANUP=1; \
echo "Stage 1: Generate go.mod with xcaddy..."; \
# Run xcaddy to generate the build directory and go.mod
GOOS=$TARGETOS GOARCH=$TARGETARCH xcaddy build v${CADDY_VERSION} \
--with github.com/greenpau/caddy-security \
--with github.com/corazawaf/coraza-caddy/v2 \
GOOS=$TARGETOS GOARCH=$TARGETARCH xcaddy build v${CADDY_TARGET_VERSION} \
--with github.com/caddyserver/caddy/v2@v${CADDY_TARGET_VERSION} \
--with github.com/greenpau/caddy-security@v${CADDY_SECURITY_VERSION} \
--with github.com/corazawaf/coraza-caddy/v2@v${CORAZA_CADDY_VERSION} \
--with github.com/hslatman/caddy-crowdsec-bouncer@v0.10.0 \
--with github.com/zhangjiayin/caddy-geoip2 \
--with github.com/mholt/caddy-ratelimit \
@@ -235,16 +278,55 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
# Patch ALL dependencies BEFORE building the final binary
# These patches fix CVEs in transitive dependencies
# Renovate tracks these via regex manager in renovate.json
# renovate: datasource=go depName=github.com/expr-lang/expr
go get github.com/expr-lang/expr@v1.17.7; \
go get github.com/expr-lang/expr@v${EXPR_LANG_VERSION}; \
# renovate: datasource=go depName=github.com/hslatman/ipstore
go get github.com/hslatman/ipstore@v0.4.0; \
# NOTE: smallstep/certificates (pulled by caddy-security stack) currently
# uses legacy nebula APIs removed in nebula v1.10+, which causes compile
# failures in authority/provisioner. Keep this pinned to a known-compatible
# v1.9.x release until upstream stack supports nebula v1.10+.
# renovate: datasource=go depName=github.com/slackhq/nebula
go get github.com/slackhq/nebula@v1.9.7; \
go get golang.org/x/net@v${XNET_VERSION}; \
# CVE-2026-33186: gRPC-Go auth bypass (fixed in v1.79.3)
# CVE-2026-34986: go-jose/v4 transitive fix (requires grpc >= v1.80.0)
# Pin here so the Caddy binary is patched immediately;
# remove once Caddy ships a release built with grpc >= v1.80.0.
# renovate: datasource=go depName=google.golang.org/grpc
go get google.golang.org/grpc@v1.80.0; \
# CVE-2026-34986: go-jose JOSE/JWT validation bypass
# renovate: datasource=go depName=github.com/go-jose/go-jose/v3
go get github.com/go-jose/go-jose/v3@v3.0.5; \
# renovate: datasource=go depName=github.com/go-jose/go-jose/v4
go get github.com/go-jose/go-jose/v4@v4.1.4; \
# CVE-2026-39883: OTel SDK resource leak
# renovate: datasource=go depName=go.opentelemetry.io/otel/sdk
go get go.opentelemetry.io/otel/sdk@v1.43.0; \
# CVE-2026-39882: OTel HTTP exporter request smuggling
# renovate: datasource=go depName=go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp
go get go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp@v0.19.0; \
# renovate: datasource=go depName=go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp
go get go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp@v1.43.0; \
# renovate: datasource=go depName=go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp
go get go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp@v1.43.0; \
# GHSA-479m-364c-43vc: goxmldsig XML signature validation bypass (loop variable capture)
# Fix available at v1.6.0. Pin here so the Caddy binary is patched immediately;
# remove once caddy-security ships a release built with goxmldsig >= v1.6.0.
# renovate: datasource=go depName=github.com/russellhaering/goxmldsig
go get github.com/russellhaering/goxmldsig@v1.6.0; \
# CVE-2026-30836: smallstep/certificates 0.30.0-rc3 vulnerability
# Fix available at v0.30.0. Pin here so the Caddy binary is patched immediately;
# remove once caddy-security ships a release built with smallstep/certificates >= v0.30.0.
go get github.com/smallstep/certificates@v${SMALLSTEP_CERTIFICATES_VERSION}; \
if [ "${CADDY_PATCH_SCENARIO}" = "A" ]; then \
# Rollback scenario: keep explicit nebula pin if upstream compatibility regresses.
# NOTE: smallstep/certificates (pulled by caddy-security stack) currently
# uses legacy nebula APIs removed in nebula v1.10+, which causes compile
# failures in authority/provisioner. Keep this pinned to a known-compatible
# v1.9.x release until upstream stack supports nebula v1.10+.
# renovate: datasource=go depName=github.com/slackhq/nebula
go get github.com/slackhq/nebula@v1.9.7; \
elif [ "${CADDY_PATCH_SCENARIO}" = "B" ] || [ "${CADDY_PATCH_SCENARIO}" = "C" ]; then \
# Default PR-2 posture: retire explicit nebula pin and use upstream resolution.
echo "Skipping nebula pin for scenario ${CADDY_PATCH_SCENARIO}"; \
else \
echo "Unsupported CADDY_PATCH_SCENARIO=${CADDY_PATCH_SCENARIO}"; \
exit 1; \
fi; \
# Clean up go.mod and ensure all dependencies are resolved
go mod tidy; \
echo "Dependencies patched successfully"; \
@@ -263,10 +345,9 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
rm -rf /tmp/buildenv_* /tmp/caddy-initial'
# ---- CrowdSec Builder ----
# Build CrowdSec from source to ensure we use Go 1.26.0+ and avoid stdlib vulnerabilities
# Build CrowdSec from source to ensure we use Go 1.26.2+ and avoid stdlib vulnerabilities
# (CVE-2025-58183, CVE-2025-58186, CVE-2025-58187, CVE-2025-61729)
# renovate: datasource=docker depName=golang versioning=docker
FROM --platform=$BUILDPLATFORM golang:1.26.0-alpine AS crowdsec-builder
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS crowdsec-builder
COPY --from=xx / /
WORKDIR /tmp/crowdsec
@@ -274,11 +355,10 @@ WORKDIR /tmp/crowdsec
ARG TARGETPLATFORM
ARG TARGETOS
ARG TARGETARCH
# CrowdSec version - Renovate can update this
# renovate: datasource=github-releases depName=crowdsecurity/crowdsec
ARG CROWDSEC_VERSION=1.7.6
# CrowdSec fallback tarball checksum (v${CROWDSEC_VERSION})
ARG CROWDSEC_RELEASE_SHA256=704e37121e7ac215991441cef0d8732e33fa3b1a2b2b88b53a0bfe5e38f863bd
ARG CROWDSEC_VERSION
ARG CROWDSEC_RELEASE_SHA256
ARG EXPR_LANG_VERSION
ARG XNET_VERSION
# hadolint ignore=DL3018
RUN apk add --no-cache git clang lld
@@ -292,10 +372,27 @@ RUN git clone --depth 1 --branch "v${CROWDSEC_VERSION}" https://github.com/crowd
# Patch dependencies to fix CVEs in transitive dependencies
# This follows the same pattern as Caddy's dependency patches
# renovate: datasource=go depName=github.com/expr-lang/expr
# renovate: datasource=go depName=golang.org/x/crypto
RUN go get github.com/expr-lang/expr@v1.17.7 && \
RUN go get github.com/expr-lang/expr@v${EXPR_LANG_VERSION} && \
go get golang.org/x/crypto@v0.46.0 && \
go get golang.org/x/net@v${XNET_VERSION} && \
# CVE-2026-33186 (GHSA-p77j-4mvh-x3m3): gRPC-Go auth bypass via missing leading slash
# Fix available at v1.79.3. Pin here so the CrowdSec binary is patched immediately;
# remove once CrowdSec ships a release built with grpc >= v1.79.3.
# renovate: datasource=go depName=google.golang.org/grpc
go get google.golang.org/grpc@v1.80.0 && \
# CVE-2026-32286: pgproto3/v2 buffer overflow (no v2 fix exists; bump pgx/v4 to latest patch)
# renovate: datasource=go depName=github.com/jackc/pgx/v4
go get github.com/jackc/pgx/v4@v4.18.3 && \
# GHSA-xmrv-pmrh-hhx2: AWS SDK v2 event stream injection
# renovate: datasource=go depName=github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream
go get github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream@v1.7.9 && \
# renovate: datasource=go depName=github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs
go get github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs@v1.69.1 && \
# renovate: datasource=go depName=github.com/aws/aws-sdk-go-v2/service/kinesis
go get github.com/aws/aws-sdk-go-v2/service/kinesis@v1.43.6 && \
# renovate: datasource=go depName=github.com/aws/aws-sdk-go-v2/service/s3
go get github.com/aws/aws-sdk-go-v2/service/s3@v1.99.1 && \
go mod tidy
# Fix compatibility issues with expr-lang v1.17.7
@@ -325,18 +422,15 @@ RUN mkdir -p /crowdsec-out/config && \
cp -r config/* /crowdsec-out/config/ || true
# ---- CrowdSec Fallback (for architectures where build fails) ----
# renovate: datasource=docker depName=alpine versioning=docker
FROM alpine:3.23.3 AS crowdsec-fallback
FROM ${ALPINE_IMAGE} AS crowdsec-fallback
SHELL ["/bin/ash", "-o", "pipefail", "-c"]
WORKDIR /tmp/crowdsec
ARG TARGETARCH
# CrowdSec version - Renovate can update this
# renovate: datasource=github-releases depName=crowdsecurity/crowdsec
ARG CROWDSEC_VERSION=1.7.6
ARG CROWDSEC_RELEASE_SHA256=704e37121e7ac215991441cef0d8732e33fa3b1a2b2b88b53a0bfe5e38f863bd
ARG CROWDSEC_VERSION
ARG CROWDSEC_RELEASE_SHA256
# hadolint ignore=DL3018
RUN apk add --no-cache curl ca-certificates
@@ -365,17 +459,17 @@ RUN set -eux; \
fi
# ---- Final Runtime with Caddy ----
FROM ${CADDY_IMAGE}
FROM ${ALPINE_IMAGE}
WORKDIR /app
# Install runtime dependencies for Charon, including bash for maintenance scripts
# Note: gosu is now built from source (see gosu-builder stage) to avoid CVEs from Debian's pre-compiled version
# Explicitly upgrade packages to fix security vulnerabilities
# binutils provides objdump for debug symbol detection in docker-entrypoint.sh
# hadolint ignore=DL3018
RUN apk add --no-cache \
bash ca-certificates sqlite-libs sqlite tzdata curl gettext libcap libcap-utils \
c-ares binutils libc-utils busybox-extras
bash ca-certificates sqlite-libs sqlite tzdata gettext libcap libcap-utils \
c-ares busybox-extras \
&& apk upgrade --no-cache zlib libcrypto3 libssl3 musl musl-utils
# Copy gosu binary from gosu-builder (built with Go 1.26+ to avoid stdlib CVEs)
COPY --from=gosu-builder /gosu-out/gosu /usr/sbin/gosu
@@ -392,12 +486,13 @@ SHELL ["/bin/ash", "-o", "pipefail", "-c"]
# Note: In production, users should provide their own MaxMind license key
# This uses the publicly available GeoLite2 database
# In CI, timeout quickly rather than retrying to save build time
ARG GEOLITE2_COUNTRY_SHA256=86fe00e0272865b8bec79defca2e9fb19ad0cf4458697992e1a37ba89077c13a
ARG GEOLITE2_COUNTRY_SHA256=62049119bd084e19fff4689bebe258f18a5f27a386e6d26ba5180941b613fc2b
RUN mkdir -p /app/data/geoip && \
if [ -n "$CI" ]; then \
if [ "$CI" = "true" ] || [ "$CI" = "1" ]; then \
echo "⏱️ CI detected - quick download (10s timeout, no retries)"; \
if curl -fSL -m 10 "https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-Country.mmdb" \
-o /app/data/geoip/GeoLite2-Country.mmdb 2>/dev/null; then \
if wget -qO /app/data/geoip/GeoLite2-Country.mmdb \
-T 10 "https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-Country.mmdb" 2>/dev/null \
&& [ -s /app/data/geoip/GeoLite2-Country.mmdb ]; then \
echo "✅ GeoIP downloaded"; \
else \
echo "⚠️ GeoIP skipped"; \
@@ -405,16 +500,12 @@ RUN mkdir -p /app/data/geoip && \
fi; \
else \
echo "Local - full download (30s timeout, 3 retries)"; \
if curl -fSL -m 30 --retry 3 "https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-Country.mmdb" \
-o /app/data/geoip/GeoLite2-Country.mmdb; then \
if echo "${GEOLITE2_COUNTRY_SHA256} /app/data/geoip/GeoLite2-Country.mmdb" | sha256sum -c -; then \
echo "✅ GeoIP checksum verified"; \
else \
echo "⚠️ Checksum failed"; \
touch /app/data/geoip/GeoLite2-Country.mmdb.placeholder; \
fi; \
if wget -qO /app/data/geoip/GeoLite2-Country.mmdb \
-T 30 -t 4 "https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-Country.mmdb" \
&& [ -s /app/data/geoip/GeoLite2-Country.mmdb ]; then \
echo "✅ GeoIP downloaded"; \
else \
echo "⚠️ Download failed"; \
echo "⚠️ GeoIP download failed or empty — skipping"; \
touch /app/data/geoip/GeoLite2-Country.mmdb.placeholder; \
fi; \
fi
@@ -425,7 +516,7 @@ COPY --from=caddy-builder /usr/bin/caddy /usr/bin/caddy
# Allow non-root to bind privileged ports (80/443) securely
RUN setcap 'cap_net_bind_service=+ep' /usr/bin/caddy
# Copy CrowdSec binaries from the crowdsec-builder stage (built with Go 1.26.0+)
# Copy CrowdSec binaries from the crowdsec-builder stage (built with Go 1.26.2+)
# This ensures we don't have stdlib vulnerabilities from older Go versions
COPY --from=crowdsec-builder /crowdsec-out/crowdsec /usr/local/bin/crowdsec
COPY --from=crowdsec-builder /crowdsec-out/cscli /usr/local/bin/cscli
@@ -540,21 +631,16 @@ EXPOSE 80 443 443/udp 2019 8080
# Security: Add healthcheck to monitor container health
# Verifies the Charon API is responding correctly
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
CMD curl -f http://localhost:8080/api/v1/health || exit 1
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
CMD wget -q -O /dev/null http://localhost:8080/api/v1/health || exit 1
# Create CrowdSec symlink as root before switching to non-root user
# This symlink allows CrowdSec to use persistent storage at /app/data/crowdsec/config
# while maintaining the expected /etc/crowdsec path for compatibility
RUN ln -sf /app/data/crowdsec/config /etc/crowdsec
# Security: Container starts as root to handle Docker socket group permissions,
# then the entrypoint script drops privileges to the charon user before starting
# applications. This approach:
# 1. Maintains CIS Docker Benchmark compliance (non-root execution)
# 2. Enables Docker integration by dynamically adding charon to docker group
# 3. Ensures proper ownership of mounted volumes
# The entrypoint script uses gosu to securely drop privileges after setup.
# Security: Run the container as non-root by default.
USER charon
# Use custom entrypoint to start both Caddy and Charon
ENTRYPOINT ["/docker-entrypoint.sh"]

View File

@@ -1,4 +1,4 @@
.PHONY: help install test build run clean docker-build docker-run release go-check gopls-logs lint-fast lint-staticcheck-only
.PHONY: help install test build run clean docker-build docker-run release go-check gopls-logs lint-fast lint-staticcheck-only security-local
# Default target
help:
@@ -22,6 +22,7 @@ help:
@echo ""
@echo "Security targets:"
@echo " security-scan - Quick security scan (govulncheck on Go deps)"
@echo " security-local - Run govulncheck + semgrep (p/golang) locally before push"
@echo " security-scan-full - Full container scan with Trivy"
@echo " security-scan-deps - Check for outdated Go dependencies"
@@ -145,6 +146,12 @@ security-scan:
@echo "Running security scan (govulncheck)..."
@./scripts/security-scan.sh
security-local: ## Run govulncheck + semgrep (p/golang) before push — fast local gate
@echo "[1/2] Running govulncheck..."
@./scripts/security-scan.sh
@echo "[2/2] Running Semgrep (p/golang, ERROR+WARNING)..."
@SEMGREP_CONFIG=p/golang ./scripts/pre-commit-hooks/semgrep-scan.sh
security-scan-full:
@echo "Building local Docker image for security scan..."
docker build --build-arg VCS_REF=$(shell git rev-parse HEAD) -t charon:local .

659
README.md
View File

@@ -1,72 +1,138 @@
<p align="center">
<img src="frontend/public/banner.png" alt="Charon" width="600">
<img src="https://raw.githubusercontent.com/Wikid82/Charon/refs/heads/main/frontend/public/banner.webp" alt="Charon" width="350">
</p>
<h1 align="center">Charon</h1>
<br>
<p align="center">
<a href="https://www.repostatus.org/#active"><img src="https://www.repostatus.org/badges/latest/active.svg" alt="Project Status: Active The project is being actively developed." /></a>
<a href="https://hub.docker.com/r/wikid82/charon"><img src="https://img.shields.io/docker/pulls/wikid82/charon.svg" alt="Docker Pulls"></a>
<a href="https://github.com/users/Wikid82/packages/container/package/charon"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/Wikid82/Charon/main/.github/badges/ghcr-downloads.json" alt="GHCR Pulls"></a>
<a href="https://github.com/Wikid82/charon/releases"><img src="https://img.shields.io/github/v/release/Wikid82/charon?include_prereleases" alt="Release"></a>
<br>
<a href="https://codecov.io/gh/Wikid82/Charon" ><img src="https://codecov.io/gh/Wikid82/Charon/branch/main/graph/badge.svg?token=RXSINLQTGE" alt="Code Coverage"/></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
<a href="SECURITY.md"><img src="https://img.shields.io/badge/Security-Audited-brightgreen.svg" alt="Security: Audited"></a>
<br>
<a href="https://github.com/Wikid82/Charon/actions/workflows/e2e-tests-split.yml"><img src="https://github.com/Wikid82/Charon/actions/workflows/e2e-tests-split.yml/badge.svg" alt="E2E Tests"></a>
<a href="https://github.com/Wikid82/Charon/actions/workflows/cerberus-integration.yml"><img src="https://github.com/Wikid82/Charon/actions/workflows/cerberus-integration.yml/badge.svg" alt="Cerberus Integration"></a><br>
<a href="https://github.com/Wikid82/Charon/actions/workflows/crowdsec-integration.yml"><img src="https://github.com/Wikid82/Charon/actions/workflows/crowdsec-integration.yml/badge.svg" alt="CrowdSec Integration"></a>
<a href="https://github.com/Wikid82/Charon/actions/workflows/waf-integration.yml"><img src="https://github.com/Wikid82/Charon/actions/workflows/waf-integration.yml/badge.svg" alt="WAF Integration"></a>
<a href="https://github.com/Wikid82/Charon/actions/workflows/rate-limit-integration.yml"><img src="https://github.com/Wikid82/Charon/actions/workflows/rate-limit-integration.yml/badge.svg" alt="Rate Limit Integration"></a>
<strong>Your server, your rules—without the headaches.</strong>
</p>
<br>
<p align="center"><strong>Your server, your rules—without the headaches.</strong></p>
<p align="center">
Simply manage multiple websites and self-hosted applications. Click, save, done. No code, no config files, no PhD required.
Manage reverse proxies with a clean web interface.<br>
No config files. No cryptic syntax. No networking degree required.
</p>
<p align="center">
<a href="https://hub.docker.com/r/wikid82/charon">
<img src="https://img.shields.io/docker/pulls/wikid82/charon.svg" alt="Docker Pulls">
</a>
<a href="https://github.com/Wikid82/charon/releases">
<img src="https://img.shields.io/github/v/release/Wikid82/charon?include_prereleases" alt="Latest Release">
</a>
<a href="LICENSE">
<img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="MIT License">
</a>
<a href="https://discord.gg/Tvzg6BQx">
<img src="https://img.shields.io/badge/Community-Discord-5865F2?logo=discord&logoColor=white">
</a>
</p>
---
## Why Charon?
## 🚀 Why Charon?
You want your apps accessible online. You don't want to become a networking expert first.
You want your apps online.
**The problem:** Managing reverse proxies usually means editing config files, memorizing cryptic syntax, and hoping you didn't break everything.
You dont want to edit config files or memorize reverse proxy syntax.
**Charon's answer:** A web interface where you click boxes and type domain names. That's it.
Charon gives you:
-**Your blog** gets a green lock (HTTPS) automatically
-**Your chat server** works without weird port numbers
-**Your admin panel** blocks everyone except you
-**Everything stays up** even when you make changes
-Automatic HTTPS certificates
-Clean domain routing
-Built-in security protection
-One-click Docker app discovery
- ✅ Live updates without restarts
- ✅ Zero external dependencies
If you can use a website, you can run Charon.
---
## 🐕 Cerberus Security Suite
## 🛡 Built-In Security
### 🕵️‍♂️ **CrowdSec Integration**
Charon includes security features that normally require multiple tools:
- Protects your applications from attacks using behavior-based detection and automated remediation.
- Web Application Firewall (WAF)
- CrowdSec intrusion detection with analytics dashboard
- Access Control Lists (ACLs)
- Rate limiting
- Emergency recovery tools
### 🔐 **Access Control Lists (ACLs)**
Secure by default. No extra containers required.
- Define fine-grained access rules for your applications, controlling who can access what and under which conditions.
### 🧱 **Web Application Firewall (WAF)**
- Protects your applications from common web vulnerabilities such as SQL injection, XSS, and more using Coraza.
### ⏱️ **Rate Limiting**
- Protect your applications from abuse by limiting the number of requests a user or IP can make within a certain timeframe.
📖 [Learn more about security →](https://wikid82.github.io/charon/security)
---
## ✨ Top 10 Features
## ⚡ Quick Start (5 Minutes)
### 1⃣ Create `docker-compose.yml`
```yaml
services:
charon:
image: wikid82/charon:latest
container_name: charon
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp"
- "8080:8080"
volumes:
- ./charon-data:/app/data
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- TZ=America/New_York
# Generate with: openssl rand -base64 32
- CHARON_ENCRYPTION_KEY=your-32-byte-base64-key
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8080/api/v1/health || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
```
> **Docker Socket Access:** Charon runs as a non-root user. If you mount the Docker socket for container discovery, the container needs permission to read it. Find your socket's group ID and add it to the compose file:
>
> ```bash
> stat -c '%g' /var/run/docker.sock
> ```
>
> Then add `group_add: ["<gid>"]` under your service (replace `<gid>` with the number from the command above). For example, if the result is `998`:
>
> ```yaml
> group_add:
> - "998"
> ```
### 2⃣ Generate encryption key
```bash
openssl rand -base64 32
```
### 3⃣ Start Charon
```bash
docker-compose up -d
```
### 4⃣ Access the dashboard
Open your browser and navigate to `http://localhost:8080` to access the dashboard and create your admin account.
```code
http://localhost:8080
```
### Getting Started
Full setup instructions and documentation are available at [https://wikid82.github.io/Charon/docs/getting-started.html](https://wikid82.github.io/Charon/docs/getting-started.html).
--- ## ✨ Top 10 Features
### 🎯 **Point & Click Management**
@@ -78,11 +144,11 @@ Free SSL certificates that request, install, and renew themselves. Your sites ge
### 🌐 **DNS Challenge for Wildcard Certificates**
Secure all your subdomains with a single `*.example.com` certificate. Supports 15+ DNS providers including Cloudflare, Route53, DigitalOcean, and Google Cloud DNS. Credentials are encrypted and automatically rotated.
Secure all your subdomains with a single *.example.com certificate. Supports 15+ DNS providers including Cloudflare, Route53, DigitalOcean, and Google Cloud DNS. Credentials are encrypted and automatically rotated.
### 🛡️ **Enterprise-Grade Security Built In**
Web Application Firewall, rate limiting, geographic blocking, access control lists, and intrusion detection via CrowdSec. Protection that "just works."
Web Application Firewall, rate limiting, geographic blocking, access control lists, and intrusion detection via CrowdSec—with a built-in analytics dashboard showing attack trends, top offenders, and ban history. Protection that "just works."
### 🔐 **Supply Chain Security**
@@ -102,15 +168,14 @@ See exactly what's happening with live request logs, uptime monitoring, and inst
### 📥 **Migration Made Easy**
Import your existing configurations with one click:
Already invested in another reverse proxy? Bring your work with you by importing your existing configurations with one click:
- **Caddyfile** — Migrate from other Caddy setups
- **Nginx** — Import from Nginx based configurations (Coming Soon)
- **Traefik** - Import from Traefik based configurations (Coming Soon)
- **CrowdSec** - Import from CrowdSec configurations (WIP)
- **CrowdSec** - Import from CrowdSec configurations
- **JSON Import** — Restore from Charon backups or generic JSON configs
Already invested in another reverse proxy? Bring your work with you.
### ⚡ **Live Configuration Changes**
Update domains, add security rules, or modify settings instantly—no container restarts needed.* Your sites stay up while you make changes.
@@ -125,498 +190,22 @@ One Docker container. No databases to install. No external services required. No
### 💯 **100% Free & Open Source**
No premium tiers. No feature paywalls. No usage limits. Everything you see is yours to use, forever, backed by the MIT license.
No premium tiers. No feature paywalls. No usage limits. Everything you see is yours to use, forever, backed by the MIT license. <sup>* Note: Initial security engine setup (CrowdSec) requires a one-time container restart to initialize the protection layer. All subsequent changes happen live.</sup> **
<sup>* Note: Initial security engine setup (CrowdSec) requires a one-time container restart to initialize the protection layer. All subsequent changes happen live.</sup>
[Explore All Features →](https://github.com/Wikid82/Charon/blob/main/docs/features.md)**
**[Explore All Features →](https://wikid82.github.io/charon/features)**
---
💬 Support
<p align="center"> <a href="https://github.com/Wikid82/Charon/issues">
<img alt="GitHub issues"
src="https://img.shields.io/github/issues/Wikid82/Charon"><a href="https://github.com/Wikid82/Charon/issues/new/choose"> <img src="https://img.shields.io/badge/Support-Open%20Issue-blue?logo=github"> </a> <a href="https://discord.gg/Tvzg6BQx"> <img src="https://img.shields.io/badge/Community-Discord-5865F2?logo=discord&logoColor=white"> </a> </p>
---
## Quick Start
❤️ Free & Open Source
### Container Registries
Charon is 100% free and open source under the MIT License.
Charon is available from two container registries:
No premium tiers. No locked features. No usage limits.
**Docker Hub (Recommended):**
```bash
docker pull wikid82/charon:latest
```
**GitHub Container Registry:**
```bash
docker pull ghcr.io/wikid82/charon:latest
```
### Docker Compose (Recommended)
Save this as `docker-compose.yml`:
```yaml
services:
charon:
# Docker Hub (recommended)
image: wikid82/charon:latest
# Alternative: GitHub Container Registry
# image: ghcr.io/wikid82/charon:latest
container_name: charon
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp"
- "8080:8080"
volumes:
- ./charon-data:/app/data
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- CHARON_ENV=production
# Generate with: openssl rand -base64 32
- CHARON_ENCRYPTION_KEY=your-32-byte-base64-key-here
```
**Using Nightly Builds:**
To test the latest nightly build (automated daily at 02:00 UTC):
```yaml
services:
charon:
# Docker Hub
image: wikid82/charon:nightly
# Alternative: GitHub Container Registry
# image: ghcr.io/wikid82/charon:nightly
# ... rest of configuration
```
> **Note:** Nightly builds are for testing and may contain experimental features. Use `latest` for production.
Then run:
```bash
docker-compose up -d
```
### Docker Run (One-Liner)
**Stable Release (Docker Hub):**
```bash
docker run -d \
--name charon \
-p 80:80 \
-p 443:443 \
-p 443:443/udp \
-p 8080:8080 \
-v ./charon-data:/app/data \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-e CHARON_ENV=production \
-e CHARON_ENCRYPTION_KEY=your-32-byte-base64-key-here \
wikid82/charon:latest
```
**Stable Release (GitHub Container Registry):**
```bash
docker run -d \
--name charon \
-p 80:80 \
-p 443:443 \
-p 443:443/udp \
-p 8080:8080 \
-v ./charon-data:/app/data \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-e CHARON_ENV=production \
-e CHARON_ENCRYPTION_KEY=your-32-byte-base64-key-here \
ghcr.io/wikid82/charon:latest
```
**Nightly Build (Testing - Docker Hub):**
```bash
docker run -d \
--name charon \
-p 80:80 \
-p 443:443 \
-p 443:443/udp \
-p 8080:8080 \
-v ./charon-data:/app/data \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-e CHARON_ENV=production \
-e CHARON_ENCRYPTION_KEY=your-32-byte-base64-key-here \
wikid82/charon:nightly
```
> **Note:** Nightly builds include the latest development features and are rebuilt daily at 02:00 UTC. Use for testing only. Also available via GHCR: `ghcr.io/wikid82/charon:nightly`
### What Just Happened?
1. Charon downloaded and started
2. The web interface opened on port 8080
3. Your websites will use ports 80 (HTTP) and 443 (HTTPS)
**Open <http://localhost:8080>** and start adding your websites!
### Requirements
**Server:**
- Docker 20.10+ or Docker Compose V2
- Linux, macOS, or Windows with WSL2
**Browser:**
- Tested with React 19.2.3
- Compatible with modern browsers:
- Chrome/Edge 90+
- Firefox 88+
- Safari 14+
- Opera 76+
> **Note:** If you encounter errors after upgrading, try a hard refresh (`Ctrl+Shift+R`) or clearing your browser cache. See [Troubleshooting Guide](docs/troubleshooting/react-production-errors.md) for details.
### Development Setup
**Requirements:**
- **go 1.26.0+** — Download from [go.dev/dl](https://go.dev/dl/)
- **Node.js 20+** and npm
- Docker 20.10+
**Install golangci-lint** (for contributors): `go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest`
**GORM Security Scanner:** Charon includes an automated security scanner that detects GORM vulnerabilities (ID leaks, exposed secrets, DTO embedding issues). Runs automatically in CI on all PRs. Run locally via:
```bash
# VS Code: Command Palette → "Lint: GORM Security Scan"
# Or via pre-commit:
pre-commit run --hook-stage manual gorm-security-scan --all-files
# Or directly:
./scripts/scan-gorm-security.sh --report
```
See [GORM Security Scanner Documentation](docs/implementation/gorm_security_scanner_complete.md) for details.
See [CONTRIBUTING.md](CONTRIBUTING.md) for complete development environment setup.
**Note:** GitHub Actions CI uses `GOTOOLCHAIN: auto` to automatically download and use go 1.26.0, even if your system has an older version installed. For local development, ensure you have go 1.26.0+ installed.
#### Keeping Go Tools Up-to-Date
After pulling a Go version update:
```bash
# Rebuild all Go development tools
./scripts/rebuild-go-tools.sh
```
**Why?** Tools like golangci-lint are compiled programs. When Go upgrades, they need to be recompiled to work with the new version. This one command rebuilds all your tools automatically.
See [Go Version Upgrades Guide](docs/development/go_version_upgrades.md) for details.
### Environment Configuration
Before running Charon or E2E tests, configure required environment variables:
1. **Copy the example environment file:**
```bash
cp .env.example .env
```
2. **Configure required secrets:**
```bash
# Generate encryption key (32 bytes, base64-encoded)
openssl rand -base64 32
# Generate emergency token (64 characters hex)
openssl rand -hex 32
```
3. **Add to `.env` file:**
```bash
CHARON_ENCRYPTION_KEY=<paste_encryption_key_here>
CHARON_EMERGENCY_TOKEN=<paste_emergency_token_here>
```
4. **Verify configuration:**
```bash
# Encryption key should be ~44 chars (base64)
grep CHARON_ENCRYPTION_KEY .env | cut -d= -f2 | wc -c
# Emergency token should be 64 chars (hex)
grep CHARON_EMERGENCY_TOKEN .env | cut -d= -f2 | wc -c
```
⚠️ **Security:** Never commit actual secret values to the repository. The `.env` file is gitignored.
📖 **More Info:** See [Getting Started Guide](docs/getting-started.md) for detailed setup instructions.
### Upgrading? Run Migrations
If you're upgrading from a previous version with persistent data:
```bash
docker exec charon /app/charon migrate
docker restart charon
```
This ensures security features (especially CrowdSec) work correctly.
**Important:** If you had CrowdSec enabled before the upgrade, it will **automatically restart** after migration. You don't need to manually re-enable it via the GUI. See [Migration Guide](https://wikid82.github.io/charon/migration-guide) for details.
---
## 🔔 Smart Notifications
Stay informed about your infrastructure with flexible notification support.
### Supported Services
Charon integrates with popular notification platforms using JSON templates for rich formatting:
- **Discord** — Rich embeds with colors, fields, and custom formatting
- **Slack** — Block Kit messages with interactive elements
- **Gotify** — Self-hosted push notifications with priority levels
- **Telegram** — Instant messaging with Markdown support
- **Generic Webhooks** — Connect to any service with custom JSON payloads
### JSON Template Examples
**Discord Rich Embed:**
```json
{
"embeds": [{
"title": "🚨 {{.Title}}",
"description": "{{.Message}}",
"color": 15158332,
"timestamp": "{{.Timestamp}}",
"fields": [
{"name": "Host", "value": "{{.HostName}}", "inline": true},
{"name": "Event", "value": "{{.EventType}}", "inline": true}
]
}]
}
```
**Slack Block Kit:**
```json
{
"blocks": [
{
"type": "header",
"text": {"type": "plain_text", "text": "🔔 {{.Title}}"}
},
{
"type": "section",
"text": {"type": "mrkdwn", "text": "*Event:* {{.EventType}}\n*Message:* {{.Message}}"}
}
]
}
```
### Available Template Variables
All JSON templates support these variables:
| Variable | Description | Example |
|----------|-------------|---------|
| `{{.Title}}` | Event title | "SSL Certificate Renewed" |
| `{{.Message}}` | Event details | "Certificate for example.com renewed" |
| `{{.EventType}}` | Type of event | "ssl_renewal", "uptime_down" |
| `{{.Severity}}` | Severity level | "info", "warning", "error" |
| `{{.HostName}}` | Affected host | "example.com" |
| `{{.Timestamp}}` | ISO 8601 timestamp | "2025-12-24T10:30:00Z" |
**[📖 Complete Notification Guide →](docs/features/notifications.md)**
---
## 🚨 Emergency Break Glass Access
Charon provides a **3-Tier Break Glass Protocol** for emergency lockout recovery when security modules (ACL, WAF, CrowdSec) block access to the admin interface.
### Emergency Recovery Quick Reference
**Tier 1 (Preferred):** Use emergency token via main endpoint
```bash
curl -X POST https://charon.example.com/api/v1/emergency/security-reset \
-H "X-Emergency-Token: $CHARON_EMERGENCY_TOKEN"
```
**Tier 2 (If Tier 1 blocked):** Use emergency server via SSH tunnel
```bash
ssh -L 2019:localhost:2019 admin@server
curl -X POST http://localhost:2019/emergency/security-reset \
-H "X-Emergency-Token: $CHARON_EMERGENCY_TOKEN" \
-u admin:password
```
**Tier 3 (Catastrophic):** Direct SSH access - see [Emergency Runbook](docs/runbooks/emergency-lockout-recovery.md)
### Tier 1: Emergency Token (Layer 7 Bypass)
**Use when:** The application is accessible but security middleware is blocking you.
```bash
# Set emergency token (generate with: openssl rand -hex 32)
export CHARON_EMERGENCY_TOKEN=your-64-char-hex-token
# Use token to disable security
curl -X POST https://charon.example.com/api/v1/emergency/security-reset \
-H "X-Emergency-Token: $CHARON_EMERGENCY_TOKEN"
```
**Response:**
```json
{
"success": true,
"message": "All security modules have been disabled",
"disabled_modules": [
"feature.cerberus.enabled",
"security.acl.enabled",
"security.waf.enabled",
"security.rate_limit.enabled",
"security.crowdsec.enabled"
]
}
```
### Tier 2: Emergency Server (Sidecar Port)
**Use when:** Caddy/CrowdSec is blocking at the reverse proxy level, or you need a separate entry point.
**Prerequisites:**
- Emergency server enabled in configuration
- SSH access to Docker host
- Knowledge of Basic Auth credentials (if configured)
**Setup:**
```yaml
# docker-compose.yml
environment:
- CHARON_EMERGENCY_SERVER_ENABLED=true
- CHARON_EMERGENCY_BIND=127.0.0.1:2019 # Localhost only
- CHARON_EMERGENCY_USERNAME=admin
- CHARON_EMERGENCY_PASSWORD=your-strong-password
```
**Usage:**
```bash
# 1. SSH to server and create tunnel
ssh -L 2019:localhost:2019 admin@server.example.com
# 2. Access emergency endpoint (from local machine)
curl -X POST http://localhost:2019/emergency/security-reset \
-H "X-Emergency-Token: $CHARON_EMERGENCY_TOKEN" \
-u admin:your-strong-password
```
### Tier 3: Direct System Access (Physical Key)
**Use when:** All application-level recovery methods have failed.
**Prerequisites:**
- SSH or console access to Docker host
- Root or sudo privileges
- Knowledge of container name
**Emergency Procedures:**
```bash
# SSH to host
ssh admin@docker-host.example.com
# Clear CrowdSec bans
docker exec charon cscli decisions delete --all
# Disable security via database
docker exec charon sqlite3 /app/data/charon.db \
"UPDATE settings SET value='false' WHERE key LIKE 'security.%.enabled';"
# Restart container
docker restart charon
```
### When to Use Each Tier
| Scenario | Tier | Solution |
|----------|------|----------|
| ACL blocked your IP | Tier 1 | Emergency token via main port |
| Caddy/CrowdSec blocking at Layer 7 | Tier 2 | Emergency server on separate port |
| Complete system failure | Tier 3 | Direct SSH + database access |
### Security Considerations
**⚠️ Emergency Server Security:**
- The emergency server should **NEVER** be exposed to the public internet
- Always bind to localhost (127.0.0.1) only
- Use SSH tunneling or VPN access to reach the port
- Optional Basic Auth provides defense in depth
- Port 2019 should be blocked by firewall rules from public access
**🔐 Emergency Token Security:**
- Store token in secrets manager (Vault, AWS Secrets Manager, Azure Key Vault)
- Rotate token every 90 days or after use
- Never commit token to version control
- Use HTTPS when calling emergency endpoint (HTTP leaks token)
- Monitor audit logs for emergency token usage
**<2A> API Key & Credential Management:**
- **Never log sensitive credentials**: Charon automatically masks API keys in logs (e.g., `abcd...xyz9`)
- **Secure storage**: CrowdSec API keys stored with 0600 permissions (owner read/write only)
- **No HTTP exposure**: API keys never returned in API responses
- **No cookie storage**: Keys never stored in browser cookies
- **Regular rotation**: Rotate CrowdSec bouncer keys every 90 days (recommended)
- **Environment variables**: Use `CHARON_SECURITY_CROWDSEC_API_KEY` for production deployments
- **Compliance**: Implementation addresses CWE-312, CWE-315, CWE-359 (GDPR, PCI-DSS, SOC 2)
For detailed security practices, see:
- 📘 [API Key Handling Guide](docs/security/api-key-handling.md)
- 🛡️ [Security Best Practices](docs/SECURITY_PRACTICES.md)
**<2A>📍 Management Network Configuration:**
```yaml
# Restrict emergency access to trusted networks only
environment:
- CHARON_MANAGEMENT_CIDRS=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
```
Default: RFC1918 private networks + localhost
### Complete Documentation
📖 **[Emergency Lockout Recovery Runbook](docs/runbooks/emergency-lockout-recovery.md)** — Complete procedures for all 3 tiers
🔄 **[Emergency Token Rotation Guide](docs/runbooks/emergency-token-rotation.md)** — Token rotation procedures
⚙️ **[Configuration Examples](docs/configuration/emergency-setup.md)** — Docker Compose and secrets manager integration
🛡️ **[Security Documentation](docs/security.md)** — Break glass protocol architecture
---
## Getting Help
**[📖 Full Documentation](https://wikid82.github.io/charon/)** — Everything explained simply
**[🚀 5-Minute Guide](https://wikid82.github.io/charon/getting-started)** — Your first website up and running
**[🔐 Supply Chain Security](docs/guides/supply-chain-security-user-guide.md)** — Verify signatures and build provenance
**[<EFBFBD> Maintenance](docs/maintenance/)** — Keeping Charon running smoothly
**[<EFBFBD>🛠 Troubleshooting](docs/troubleshooting/)** — Common issues and solutions
**[💬 Ask Questions](https://github.com/Wikid82/charon/discussions)** — Friendly community help
**[🐛 Report Problems](https://github.com/Wikid82/charon/issues)** — Something broken? Let us know
---
Built for the self-hosting community.

File diff suppressed because it is too large Load Diff

View File

@@ -19,36 +19,80 @@ Example: `0.1.0-alpha`, `1.0.0-beta.1`, `2.0.0-rc.2`
## Creating a Release
### Automated Release Process
### Canonical Release Process (Tag-Derived CI)
1. **Update version** in `.version` file:
1. **Create and push a release tag**:
```bash
echo "1.0.0" > .version
git tag -a v1.0.0 -m "Release v1.0.0"
git push origin v1.0.0
```
2. **Commit version bump**:
2. **GitHub Actions automatically**:
- Runs release workflow from the pushed tag (`.github/workflows/release-goreleaser.yml`)
- Builds and publishes release artifacts/images through CI (`.github/workflows/docker-build.yml`)
- Creates/updates GitHub Release metadata
3. **Container tags are published**:
- `v1.0.0` (exact version)
- `1.0` (minor version)
- `1` (major version)
- `latest` (for non-prerelease on main branch)
### Legacy/Optional `.version` Path
The `.version` file is optional and not the canonical release trigger.
Use it only when you need local/version-file parity checks:
1. **Set `.version` locally (optional)**:
```bash
git add .version
git commit -m "chore: bump version to 1.0.0"
echo "1.0.0" > .version
```
3. **Create and push tag**:
1. **Validate `.version` matches the latest tag**:
```bash
git tag -a v1.0.0 -m "Release v1.0.0"
git push origin v1.0.0
bash scripts/check-version-match-tag.sh
```
4. **GitHub Actions automatically**:
- Creates GitHub Release with changelog
- Builds multi-arch Docker images (amd64, arm64)
- Publishes to GitHub Container Registry with tags:
- `v1.0.0` (exact version)
- `1.0` (minor version)
- `1` (major version)
- `latest` (for non-prerelease on main branch)
### Deterministic Rollout Verification Gates (Mandatory)
Release sign-off is blocked until all items below pass in the same validation
run.
Enforcement points:
- Release sign-off checklist/process (mandatory): All gates below remain required for release sign-off.
- CI-supported checks (current): `.github/workflows/docker-build.yml` and `.github/workflows/supply-chain-verify.yml` enforce the subset currently implemented in workflows.
- Manual validation required until CI parity: Validate any not-yet-implemented workflow gates via VS Code tasks `Security: Full Supply Chain Audit`, `Security: Verify SBOM`, `Security: Generate SLSA Provenance`, and `Security: Sign with Cosign`.
- Optional version-file parity check: `Utility: Check Version Match Tag` (script: `scripts/check-version-match-tag.sh`).
- [ ] **Digest freshness/parity:** Capture pre-push and post-push index digests
for the target tag in GHCR and Docker Hub, confirm expected freshness,
and confirm cross-registry index digest parity.
- [ ] **Per-arch parity:** Confirm per-platform (`linux/amd64`, `linux/arm64`,
and any published platform) digest parity between GHCR and Docker Hub.
- [ ] **Immutable digest scanning:** Run SBOM and vulnerability scans against
immutable refs only, using `image@sha256:<index-digest>`.
- [ ] **Artifact freshness:** Confirm scan artifacts are generated after the
push timestamp and in the same validation run.
- [ ] **Evidence block present:** Include the mandatory evidence block fields
listed below.
#### Mandatory Evidence Block Fields
- Tag name
- Index digest (`sha256:...`)
- Per-arch digests (platform -> digest)
- Scan tool versions
- Push timestamp and scan timestamp(s)
- Artifact file names generated in this run
## Container Image Tags

Some files were not shown because too many files have changed in this diff Show More