Skip to content

ci: add CI and take the quality gates from base-repo#7

Merged
sinkog merged 8 commits into
mainfrom
feat/quality-gates
Jul 17, 2026
Merged

ci: add CI and take the quality gates from base-repo#7
sinkog merged 8 commits into
mainfrom
feat/quality-gates

Conversation

@sinkog

@sinkog sinkog commented Jul 17, 2026

Copy link
Copy Markdown
Member

Brings this repository's quality gates up to what base-repo's mcp branch got today, and adds the CI that enforces them.

The manifest-driven design is untouched: knowledge.sources.yaml stays the declared desired state, .gitmodules stays a generated artifact. This is about tightening what surrounds it.

Why now

This repository had no CI: no workflow, no runs, an unprotected main. Nothing ran the linters, the type checker, or the tests — so all three had drifted, exactly as base-repo's mcp branch had. Most of these files were byte-identical to base-repo's before today, so the fixes port across unchanged.

What lands

Quality config, from base-repo mcp/main — .yamllint (indent-sequences: consistent, since the generated companions use PyYAML's block style and hand-written YAML indents), .bandit (skips with their reasons, replacing a run that failed on the import of subprocess), and mypy stub overrides.

CI, retriggered for this repo's branches, plus one step base-repo cannot run: rendering .gitmodules from knowledge.sources.yaml. There is nothing to diff against — the file is gitignored — but rendering fails on a malformed manifest, and that manifest is what this repository is built around. Verified: it exits 1 on a broken kind:.

This also puts test_mcp_server_write_confinement.py — the proof that the write tools cannot escape SOURCE_DIR — under automation for the first time.

Fixes, ported from base-repo. Three were real:

  • a dead file_path in search_code, left over from when file_paths replaced the single path
  • _watch_loop passed Path | None into _scan_watch_dir. Unlike base-repo, the loop is live here — threading.Thread starts it — so it now states its precondition instead of failing deeper.
  • the ManualInterventionRequired handler: a release stopping for a human exited 1 instead of 0. The exception class survived, the handler did not.

validate removed. It announced "Validating all schemas against the meta-schema" and did nothing: run_validation() is commented out with "Assuming a validation method exists" and no such method exists. Upstream it resolves sources/index.yaml — CIC_Schemas territory. This repository has no canonical schema source. What could sensibly be validated here is companion YAML against the meta-schemas and knowledge.sources.yaml; the CI now covers the latter. CLI is {check,prepare,close}.

Tests repointed at the phase API. They still described the design that run_release_close was split out of, while ReleaseManager already exposes run_check / run_prepare_release / run_finalize_release. Remapped by what each asserts. Two were deleted with their subjects. One was a false green: release had stopped being a valid command, so argparse exited 2 before the assertion meant anything.

Result

before after
CI none green
ruff 30 0
yamllint 648 0
mypy 12 0
bandit 4 0
tests 17 failed, 128 passed 143 passed

Not in this PR

The code sync from base-repo — make_source.py (+143 lines), server.py (+292), kb_watch.py (+261). That is not a version gap but a design difference: base-repo drives the watcher as a subprocess over watchdog, this repo runs it in-process on a thread. Adopting it is an architectural decision, not a sync.

knowledge.sources.yaml still points cic-basic-knowledge at github_private. Repointing it at the new cic-knowledge repo is ready and waiting on its own branch.

.bandit skips are global: a new shell=True anywhere in tools/ would now pass unflagged. A per-call # nosec B602 would be narrower if that trade stops being acceptable.

tools/infra.py keeps import requests # noqa: F401 — nothing calls it, but test_infra patches tools.infra.requests.get. Both go when those tests are properly rewritten.

Gábor Z Sinkó added 8 commits July 17, 2026 09:03
Ported from base-repo mcp/main, where these were worked out today:

  .yamllint      indent-sequences: consistent — the generated companions
                 use PyYAML's block style, hand-written YAML indents; each
                 file only has to be internally consistent. Also drops the
                 file-rules block: yamllint has no such key, so that
                 document-start override never took effect.
  .bandit        skips with their reasons (B602 shell=True in the accept
                 gate, B404, B112), replacing a run that failed on every
                 finding including the import of subprocess.
  pyproject.toml mypy stub overrides for langdetect and rank_bm25.

Result here: yamllint 648 errors -> 0, bandit 4 findings -> 0.

---
[signing-metadata]
key = cic-my-sign-key
signature = vault:v1:MEYCIQCyPxYQeHn8GNnfNntwfJnaFs8mD5kareg/Z/U5e7qfHAIhAJYr1Fg9xlndjz+JFuUea+aknhQFl5BFj+g9SyDNajnN
hash-algorithm = sha256
digest = h5BNgOX49f7IbQJ+1Ms76oJZ6c9AE2Xi4b1Mhkw1Bto=

[certificate]
-----BEGIN CERTIFICATE-----
MIICBjCCAaygAwIBAgIUSnRMR6RPnEbg296XWPOqq/u5PCwwCgYIKoZIzj0EAwIw
QzELMAkGA1UEBhMCSFUxGTAXBgNVBAoMEENlbnRyYWxJbmZyYUNvcmUxGTAXBgNV
BAMMEENJQyBEZXZlbG9wZXIgQ0EwHhcNMjYwMzIwMTMyMjU5WhcNMjYxMjMxMTMy
MjU5WjBFMQswCQYDVQQGEwJIVTEZMBcGA1UECgwQQ2VudHJhbEluZnJhQ29yZTEb
MBkGA1UEAwwSR2Fib3IgWm9sdGFuIFNpbmtvMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEIG2CVmTfmLB9pLLclj7YmP2eedAjklpy4LGrU2ijoiy6Xqpuybv7OgJe
i+ez31s65NEV8+X/ByeX1cstR988z6N8MHowCQYDVR0TBAIwADAdBgNVHQ4EFgQU
yZN6AIX/TNnIJ9GwAa/NRN3ujHAwHwYDVR0jBBgwFoAUXn6CHYzPUqU4JVP8g+OS
WeDYjhcwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF
BQcDBDAKBggqhkjOPQQDAgNIADBFAiEA+bFzXRoJ4PCQbhAAtpkcMjt0vNj5rEW0
lOMBGDNyaWkCIB1vmM7PcZzv/c9bIrxF5kqv6QXomouhByUfeNUTbpKW
-----END CERTIFICATE-----
This repository had none: no workflow, no runs, an unprotected main. That
is how its lockfile, linters and tests all drifted unseen — the same way
base-repo's mcp branch did.

Modelled on base-repo mcp/main, retriggered for this repo's branches
(main, feat/**, fix/**, chore/**) and with one step base-repo cannot run:
rendering .gitmodules from knowledge.sources.yaml. .gitmodules is
generated and gitignored, so there is nothing to diff — but rendering
fails on a malformed manifest, and that manifest is what this repository
is built around. Verified: it exits 1 on a broken 'kind:'.

This also puts tests/test_tools/test_mcp_server_write_confinement.py — the
proof that the write tools cannot escape SOURCE_DIR — under automation for
the first time.

---
[signing-metadata]
key = cic-my-sign-key
signature = vault:v1:MEYCIQD9uhzDxE+vVJMnqcBgY0FNDSa3rzQxWkE1DK1K4CpaMwIhAMfg5fhRrTfAdPaDOufOq+EYfUpi9FJdAui+ZemZZsfb
hash-algorithm = sha256
digest = u1+JyeiPd0vuERosKXNZKqfi4YaqNvlLm/iE36pJUgA=

[certificate]
-----BEGIN CERTIFICATE-----
MIICBjCCAaygAwIBAgIUSnRMR6RPnEbg296XWPOqq/u5PCwwCgYIKoZIzj0EAwIw
QzELMAkGA1UEBhMCSFUxGTAXBgNVBAoMEENlbnRyYWxJbmZyYUNvcmUxGTAXBgNV
BAMMEENJQyBEZXZlbG9wZXIgQ0EwHhcNMjYwMzIwMTMyMjU5WhcNMjYxMjMxMTMy
MjU5WjBFMQswCQYDVQQGEwJIVTEZMBcGA1UECgwQQ2VudHJhbEluZnJhQ29yZTEb
MBkGA1UEAwwSR2Fib3IgWm9sdGFuIFNpbmtvMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEIG2CVmTfmLB9pLLclj7YmP2eedAjklpy4LGrU2ijoiy6Xqpuybv7OgJe
i+ez31s65NEV8+X/ByeX1cstR988z6N8MHowCQYDVR0TBAIwADAdBgNVHQ4EFgQU
yZN6AIX/TNnIJ9GwAa/NRN3ujHAwHwYDVR0jBBgwFoAUXn6CHYzPUqU4JVP8g+OS
WeDYjhcwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF
BQcDBDAKBggqhkjOPQQDAgNIADBFAiEA+bFzXRoJ4PCQbhAAtpkcMjt0vNj5rEW0
lOMBGDNyaWkCIB1vmM7PcZzv/c9bIrxF5kqv6QXomouhByUfeNUTbpKW
-----END CERTIFICATE-----
Identical to base-repo's: 'make validate' announced 'Validating all
schemas against the meta-schema' and did nothing — run_validation() is
commented out with 'Assuming a validation method exists', and
ReleaseManager has no such method. A gate that reports success without
checking anything is worse than none.

The upstream implementation (main, wasm/main, schemas/main) resolves
canonical_source_file / sources/index.yaml — CIC_Schemas territory. This
repository has no canonical schema source. What could sensibly be
validated here is companion YAML against md/py/go.meta.schema.yaml and
knowledge.sources.yaml, which is a different command; the CI now renders
the manifest, which covers the latter.

CLI is now {check,prepare,close}.

---
[signing-metadata]
key = cic-my-sign-key
signature = vault:v1:MEYCIQDL6wNuUaQB46BKLm6ky0/5hAagYU4EO59Fw23qogfp0wIhANMNSM+0Ca4OV6q3g9gpnBhEGHt30oaiGWKCpRDk8B2b
hash-algorithm = sha256
digest = 5SMIZx9eAy41cpfAviVHUHoofUMKl3KspTzImS1J2xc=

[certificate]
-----BEGIN CERTIFICATE-----
MIICBjCCAaygAwIBAgIUSnRMR6RPnEbg296XWPOqq/u5PCwwCgYIKoZIzj0EAwIw
QzELMAkGA1UEBhMCSFUxGTAXBgNVBAoMEENlbnRyYWxJbmZyYUNvcmUxGTAXBgNV
BAMMEENJQyBEZXZlbG9wZXIgQ0EwHhcNMjYwMzIwMTMyMjU5WhcNMjYxMjMxMTMy
MjU5WjBFMQswCQYDVQQGEwJIVTEZMBcGA1UECgwQQ2VudHJhbEluZnJhQ29yZTEb
MBkGA1UEAwwSR2Fib3IgWm9sdGFuIFNpbmtvMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEIG2CVmTfmLB9pLLclj7YmP2eedAjklpy4LGrU2ijoiy6Xqpuybv7OgJe
i+ez31s65NEV8+X/ByeX1cstR988z6N8MHowCQYDVR0TBAIwADAdBgNVHQ4EFgQU
yZN6AIX/TNnIJ9GwAa/NRN3ujHAwHwYDVR0jBBgwFoAUXn6CHYzPUqU4JVP8g+OS
WeDYjhcwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF
BQcDBDAKBggqhkjOPQQDAgNIADBFAiEA+bFzXRoJ4PCQbhAAtpkcMjt0vNj5rEW0
lOMBGDNyaWkCIB1vmM7PcZzv/c9bIrxF5kqv6QXomouhByUfeNUTbpKW
-----END CERTIFICATE-----
Ported from base-repo mcp/main — these files were byte-identical before
today, so the fixes apply unchanged.

Real ones:
  - a dead file_path in search_code, left behind when
    _extract_chunk_file_paths / file_paths replaced the single path
  - _watch_loop passed Path | None into _scan_watch_dir. Unlike base-repo,
    the loop is live here (threading.Thread starts it), so it now states
    its precondition rather than failing deeper with a TypeError.
  - the ManualInterventionRequired handler, restored with tools/compiler.py:
    a release stopping for a human exited 1 instead of 0.

Mechanical: unused imports, redundant re-imports inside test methods,
f-strings without placeholders, five single-line if/with statements, and
two variables reused at two types in one scope ('f' as Path then file
handle, 'm' as Match then optional Match).

tools/infra.py keeps 'import requests  # noqa: F401' — nothing calls it,
but test_infra patches tools.infra.requests.get, so the name must exist.
Both go when those tests are repaired.

ruff 30 -> 0, mypy 12 -> 0.

---
[signing-metadata]
key = cic-my-sign-key
signature = vault:v1:MEUCIDY7sswbGEW+5QQhS5KUlNRcSX8nMwcfx575bJQjQtL6AiEA2JGduA5VtQdSL+y/i2tI2A/7Tlt7dh//Q4KkALNysLI=
hash-algorithm = sha256
digest = 3M+xnjqOOVTv6k92EaGHRhDIIVU8rRSoxhNIwi9ijzk=

[certificate]
-----BEGIN CERTIFICATE-----
MIICBjCCAaygAwIBAgIUSnRMR6RPnEbg296XWPOqq/u5PCwwCgYIKoZIzj0EAwIw
QzELMAkGA1UEBhMCSFUxGTAXBgNVBAoMEENlbnRyYWxJbmZyYUNvcmUxGTAXBgNV
BAMMEENJQyBEZXZlbG9wZXIgQ0EwHhcNMjYwMzIwMTMyMjU5WhcNMjYxMjMxMTMy
MjU5WjBFMQswCQYDVQQGEwJIVTEZMBcGA1UECgwQQ2VudHJhbEluZnJhQ29yZTEb
MBkGA1UEAwwSR2Fib3IgWm9sdGFuIFNpbmtvMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEIG2CVmTfmLB9pLLclj7YmP2eedAjklpy4LGrU2ijoiy6Xqpuybv7OgJe
i+ez31s65NEV8+X/ByeX1cstR988z6N8MHowCQYDVR0TBAIwADAdBgNVHQ4EFgQU
yZN6AIX/TNnIJ9GwAa/NRN3ujHAwHwYDVR0jBBgwFoAUXn6CHYzPUqU4JVP8g+OS
WeDYjhcwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF
BQcDBDAKBggqhkjOPQQDAgNIADBFAiEA+bFzXRoJ4PCQbhAAtpkcMjt0vNj5rEW0
lOMBGDNyaWkCIB1vmM7PcZzv/c9bIrxF5kqv6QXomouhByUfeNUTbpKW
-----END CERTIFICATE-----
Same rot as base-repo, and from the same commit: the tests still describe
the design that one run_release_close dispatcher was split out of, while
ReleaseManager here already exposes run_check / run_prepare_release /
run_finalize_release. They had not run since collection broke.

Remapped by what each asserts: developer preparation -> run_prepare_release,
finalization -> run_finalize_release, vault-not-initialized -> run_check
(the guard lives there), the release CLI command -> close. Deleted
test_api_accessibility_check_failure and test_validate_command_success with
their subjects. Fixed a false green where 'release' being an invalid command
made argparse exit 2 before the assertion could mean anything.

143 passed, including the 10 write-confinement tests.

---
[signing-metadata]
key = cic-my-sign-key
signature = vault:v1:MEUCIFI1c8HCeyUEbuIrJLT2cRIWjNW63AIz9dhF3EVG9829AiEA6vZFZgPNaD4HHL4HD+cxGVlIMO6t7REFYGlbmQf8QXI=
hash-algorithm = sha256
digest = dI1aqpv8ahCn5+S6jFttGyin29iA+lULiCj85b3TFNI=

[certificate]
-----BEGIN CERTIFICATE-----
MIICBjCCAaygAwIBAgIUSnRMR6RPnEbg296XWPOqq/u5PCwwCgYIKoZIzj0EAwIw
QzELMAkGA1UEBhMCSFUxGTAXBgNVBAoMEENlbnRyYWxJbmZyYUNvcmUxGTAXBgNV
BAMMEENJQyBEZXZlbG9wZXIgQ0EwHhcNMjYwMzIwMTMyMjU5WhcNMjYxMjMxMTMy
MjU5WjBFMQswCQYDVQQGEwJIVTEZMBcGA1UECgwQQ2VudHJhbEluZnJhQ29yZTEb
MBkGA1UEAwwSR2Fib3IgWm9sdGFuIFNpbmtvMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEIG2CVmTfmLB9pLLclj7YmP2eedAjklpy4LGrU2ijoiy6Xqpuybv7OgJe
i+ez31s65NEV8+X/ByeX1cstR988z6N8MHowCQYDVR0TBAIwADAdBgNVHQ4EFgQU
yZN6AIX/TNnIJ9GwAa/NRN3ujHAwHwYDVR0jBBgwFoAUXn6CHYzPUqU4JVP8g+OS
WeDYjhcwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF
BQcDBDAKBggqhkjOPQQDAgNIADBFAiEA+bFzXRoJ4PCQbhAAtpkcMjt0vNj5rEW0
lOMBGDNyaWkCIB1vmM7PcZzv/c9bIrxF5kqv6QXomouhByUfeNUTbpKW
-----END CERTIFICATE-----
Every tracked file is checksummed, so this branch's changes invalidate it.
The CI now runs manifest-verify, which makes regenerating part of any
change from here on.

---
[signing-metadata]
key = cic-my-sign-key
signature = vault:v1:MEYCIQDeHoQ2UAOM9fD081ZCMBgORnIgA4ur4gqpujT5ICUo8gIhANb5X+4z3gPZU9l+DSp8+2dbQx6M8cEBo3LnxyDweq9C
hash-algorithm = sha256
digest = DwicT5xZqaTPEZ0M5HgtI5wH9OXPodzmk/rXXG4KIpM=

[certificate]
-----BEGIN CERTIFICATE-----
MIICBjCCAaygAwIBAgIUSnRMR6RPnEbg296XWPOqq/u5PCwwCgYIKoZIzj0EAwIw
QzELMAkGA1UEBhMCSFUxGTAXBgNVBAoMEENlbnRyYWxJbmZyYUNvcmUxGTAXBgNV
BAMMEENJQyBEZXZlbG9wZXIgQ0EwHhcNMjYwMzIwMTMyMjU5WhcNMjYxMjMxMTMy
MjU5WjBFMQswCQYDVQQGEwJIVTEZMBcGA1UECgwQQ2VudHJhbEluZnJhQ29yZTEb
MBkGA1UEAwwSR2Fib3IgWm9sdGFuIFNpbmtvMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEIG2CVmTfmLB9pLLclj7YmP2eedAjklpy4LGrU2ijoiy6Xqpuybv7OgJe
i+ez31s65NEV8+X/ByeX1cstR988z6N8MHowCQYDVR0TBAIwADAdBgNVHQ4EFgQU
yZN6AIX/TNnIJ9GwAa/NRN3ujHAwHwYDVR0jBBgwFoAUXn6CHYzPUqU4JVP8g+OS
WeDYjhcwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF
BQcDBDAKBggqhkjOPQQDAgNIADBFAiEA+bFzXRoJ4PCQbhAAtpkcMjt0vNj5rEW0
lOMBGDNyaWkCIB1vmM7PcZzv/c9bIrxF5kqv6QXomouhByUfeNUTbpKW
-----END CERTIFICATE-----
ruff --fix: pickle/tempfile/pytest in test_make_source, pytest and the
per-method 'import server as mcp_server' in test_mcp_server (the module
already imports it), Path in the write-confinement test. None are
referenced; the suite stays at 143 passed.

---
[signing-metadata]
key = cic-my-sign-key
signature = vault:v1:MEUCIQC9+q0eFB6cH2t1WbIQFUvz3uwR3AS7KHH+QRuuUoAWlQIgJgW2wqinik25DsHAJ1uSTAaEd8FadbZOX8u71LXIiKo=
hash-algorithm = sha256
digest = LJDTrUAPZmFfht3ij60ETjpbEDL7P9Ejtdp2+rFo3jk=

[certificate]
-----BEGIN CERTIFICATE-----
MIICBjCCAaygAwIBAgIUSnRMR6RPnEbg296XWPOqq/u5PCwwCgYIKoZIzj0EAwIw
QzELMAkGA1UEBhMCSFUxGTAXBgNVBAoMEENlbnRyYWxJbmZyYUNvcmUxGTAXBgNV
BAMMEENJQyBEZXZlbG9wZXIgQ0EwHhcNMjYwMzIwMTMyMjU5WhcNMjYxMjMxMTMy
MjU5WjBFMQswCQYDVQQGEwJIVTEZMBcGA1UECgwQQ2VudHJhbEluZnJhQ29yZTEb
MBkGA1UEAwwSR2Fib3IgWm9sdGFuIFNpbmtvMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEIG2CVmTfmLB9pLLclj7YmP2eedAjklpy4LGrU2ijoiy6Xqpuybv7OgJe
i+ez31s65NEV8+X/ByeX1cstR988z6N8MHowCQYDVR0TBAIwADAdBgNVHQ4EFgQU
yZN6AIX/TNnIJ9GwAa/NRN3ujHAwHwYDVR0jBBgwFoAUXn6CHYzPUqU4JVP8g+OS
WeDYjhcwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF
BQcDBDAKBggqhkjOPQQDAgNIADBFAiEA+bFzXRoJ4PCQbhAAtpkcMjt0vNj5rEW0
lOMBGDNyaWkCIB1vmM7PcZzv/c9bIrxF5kqv6QXomouhByUfeNUTbpKW
-----END CERTIFICATE-----
This repo's docker-compose.yml reads LOCAL_UID/LOCAL_GID; base-repo's,
which the workflow was copied from, reads UID/GID. So the container ran as
the default 1000 while the runner is 1001, and pip-compile could not write
the .pip-cache bind mount it had just been handed.

This repo's spelling is the better one — UID is shell-internal and does not
export reliably — which is worth carrying back to base-repo.

---
[signing-metadata]
key = cic-my-sign-key
signature = vault:v1:MEUCIQD2r8Kp3gqu+H4c0wU7Ty+2jUYMVU8NBPH/aCHCGIO2QwIgHXr3qg8C+iM1rbOJdfGTAuRdtsEuAtaEXY8BvgjgxuU=
hash-algorithm = sha256
digest = r8xeR/myUJAop2gRkoUsYL7nROy1b87pSEeHDqOLgBc=

[certificate]
-----BEGIN CERTIFICATE-----
MIICBjCCAaygAwIBAgIUSnRMR6RPnEbg296XWPOqq/u5PCwwCgYIKoZIzj0EAwIw
QzELMAkGA1UEBhMCSFUxGTAXBgNVBAoMEENlbnRyYWxJbmZyYUNvcmUxGTAXBgNV
BAMMEENJQyBEZXZlbG9wZXIgQ0EwHhcNMjYwMzIwMTMyMjU5WhcNMjYxMjMxMTMy
MjU5WjBFMQswCQYDVQQGEwJIVTEZMBcGA1UECgwQQ2VudHJhbEluZnJhQ29yZTEb
MBkGA1UEAwwSR2Fib3IgWm9sdGFuIFNpbmtvMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEIG2CVmTfmLB9pLLclj7YmP2eedAjklpy4LGrU2ijoiy6Xqpuybv7OgJe
i+ez31s65NEV8+X/ByeX1cstR988z6N8MHowCQYDVR0TBAIwADAdBgNVHQ4EFgQU
yZN6AIX/TNnIJ9GwAa/NRN3ujHAwHwYDVR0jBBgwFoAUXn6CHYzPUqU4JVP8g+OS
WeDYjhcwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF
BQcDBDAKBggqhkjOPQQDAgNIADBFAiEA+bFzXRoJ4PCQbhAAtpkcMjt0vNj5rEW0
lOMBGDNyaWkCIB1vmM7PcZzv/c9bIrxF5kqv6QXomouhByUfeNUTbpKW
-----END CERTIFICATE-----
@sinkog
sinkog merged commit 1fccec2 into main Jul 17, 2026
2 checks passed
@sinkog
sinkog deleted the feat/quality-gates branch July 17, 2026 09:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant