Repository navigation
Releases: sowoi/check-opencloud-security
Release list
v1.31.2
check-opencloud-security 1.31.2
Security
- The erasure credential throttle counts an IPv6 client by its /64. Failed
guesses at theDELETE /api/purgetoken were counted per single address,
while every other limit counts an IPv6 client by the /64 it is handed - so
rotating the interface identifier bought five fresh guesses each time. The
32-character minimum on the token kept guessing impractical regardless. - The scan service refuses a guessable token on a wide bind. Serving
anywhere but loopback required a token but accepted any non-empty one -
--token a, or the placeholdersecrets/scanner_token.exampleships with -
and nothing counts failed attempts, so a short token let anybody who reached
the port make it scan whatever they named. Such a bind now needs a token of
at least 32 characters that is not that placeholder, or it refuses to start.
openssl rand -hex 32, which every guide already uses, is unaffected.
Fixed
- A check only one of two scans made is no longer called new or resolved.
Comparisons read a finding missing from the earlier scan as passing, so a
check added by a newer scanner - or by turning the extra checks on - was
reported as a regression of the instance, and a check the later scan no
longer made as fixed. The baseline,check-opencloud-scanner diff, the web
comparison andcompare_scansnow list these as newly measured or no
longer measured, based on each scan's coverage block, and the explanation
files them as scanner changes. A newly measured failure still alerts, and
--warn-on-newstill does not suppress it. A report or baseline that does
not list its checks is compared as before. See ADR 0079. - Aligned the report expiry footer, warning and live countdown to round remaining
minutes up consistently in every language. - A comparison page rounds its expiry up too. It rounded the minutes
left down, so it announced one minute fewer than the result page would.
Documentation
-
Added German, Spanish and French operator architecture and operations documentation, including
localized document navigation and operator search. Section anchors and commands
remain aligned with English; ADRs and release-note bodies remain English. -
Clarified grouped remediation, upgrade estimates, report expiry and operator
messages in English, German, Spanish and French. A simulated upgrade whose
grade is limited by findings no longer implies that the grade cannot improve.
Count labels also read correctly for a single finding. -
Expanded all-language tests for remediation groups, upgrade estimates,
escaped version strings, singular and plural expiry warnings, and the
translated decision-record interface around English source documents. -
Decision records are never translated. ADR 0077 records that every
record inadr/exists in English only, and once: the operator area shows
it untranslated in every locale, and translation work leavesadr/alone. -
Changelogs and release notes are never translated. ADR 0078 records
thatCHANGELOG.md,RELEASE.mdand the GitHub release body exist in
English only, and that the operator area's Releases tab shows them
untranslated in every locale.
What's Changed
Full Changelog: v1.31.1...v1.31.2
v1.31.1
check-opencloud-security 1.31.1
Changed
- The coverage warning's alert line is now covered by mutation testing.
tests/test_coverage_regression.pydrives_apply_baselinein process but
was missing from the mutmut selection, so eleven mutants of the branch that
lifts an OK to WARNING when a measured check turns inconclusive survived.
It is now listed, and its test asserts the whole alert line: three of those
mutants leftOK:inside the WARNING message without a test noticing.
Fixed
- The web report no longer offers "What gets you to A+" under an A+. When
no step in the remediation plan raises the grade, because the instance
already has the top grade or something no setting can change holds it down,
the plan is headed "Still worth fixing, the grade stays A+" (or whichever
grade it holds) instead.
This applies to the dashboard, its contents list, and the PDF and HTML
exports, in all four languages. check-opencloud-scanner fleetlists waiver deadlines in the order they
end. Deadlines were sorted by their text, so a waiver written with a
+02:00offset could be listed after one that ends later in UTC.- The fleet summary's "Not covered" count counts each host once. A host
whose last scan failed long enough ago to be stale was counted twice. - The remediation plan no longer fails on a result document whose
ratingExplanation.baseisnull. The update step's detail is then left
empty, instead ofremediation_plan()raising.
Security
- An empty listen address no longer counts as loopback for the scan
service. Binding""listens on every interface, but the check that
demands a token for anything but loopback let it through. The command line,
COS_SERVICE_LISTENand the configuration file all fall back to
127.0.0.1when empty, so only a program callingbuild_server()or
serve()withlisten=""could reach it. - The container images install the dependencies
uv.lockpins, with their
hashes. Bothdocker/Dockerfileanddocker/Dockerfile.webresolved
their dependencies from PyPI at build time, so an image could ship versions
that CI,pip-auditand the SBOM never saw.
What's Changed
Full Changelog: v1.31.0...v1.31.1
v1.31.0
check-opencloud-security 1.31.0
Documentation
- Polished scan progress, errors, downloads and sharing text in English,
German, Spanish and French. Corrected informal Spanish instructions and
clarified that saved downloads remain available after a scan expires. - Updated all four web-service guides to describe every export format,
including offline HTML reports and remediation bundles. Expanded tests for
translated error pages, email drafts, link-free summaries and download links. - Translation checks now catch additional Spanish forms of informal address
and report broken guide links at their original line numbers, ignoring
links shown only in code examples. Added regression tests for both cases.
Added
- Coverage regression alerts. With
--baseline, a check that an earlier
run reached a conclusion on and that isinconclusivenow raises anOKto
WARNING, even when the grade has not moved. The rating, its perfdata and
the findings are untouched: the scan saw less, the instance did not change.
The warning lasts until the check is measured again,--warn-on-newdoes
not suppress it, the webhook'sbaseline_diffcarries the lost checks as
coverage_regressed, and the two-document comparison reports a
coverageRegressedscanner change. See ADR 0074 and
Reporting only what changed. - Grouped remediation plans.
remediationPlan.groupsplaces every open
finding in the system its fix is made in - the reverse proxy, the identity
provider, OpenCloud or the DNS zone - and merges the findings one edit
resolves into a single change: every missing header is one header block,
every exposed path one proxy rule, and the update closes every matching
advisory. Each change carries the rating it alone would give, replayed
through the rating function, andgroupSummarynames the changes that
resolve several findings at once. Shown by--debug, on the web dashboard
("What to change where"), in the remediation bundle, and returned by the
plan_remediationMCP tool. See ADR 0075 and
What would raise the rating. - Architecture decisions in the operator area. A new Decisions tab at
/admin/decisionslists every architecture decision record with its
status, and a filter narrows the list by number, title or status. Each
record opens as its own page in English, and links between records, or from
the Architecture tab, stay inside the area. The area's search now indexes
every record's full text. Like the rest of the area, the records are never
public: a stranger gets a 404, and they are absent from the public search,
the sitemap and/documentation. check-opencloud-scanner review-waivers. It reads the configured
waivers (ignore_hardeningsandtemporary_waivers, or the
--ignore-hardeningand--waive-untilvalues given to it) and lists five
kinds that need attention. Expired waivers no longer suppress anything.
Expiring soon ones run out within thewaiver_warningwindow. Unused
ones match no failing check in a--resultdocument, or with no document,
no identifier the scanner knows. Overlapping ones are already covered by
another waiver, such as a deadline hidden under a permanent*.
Permanent ones have no reason and no deadline. Each item has a suggested
cleanup, for a permanent waiver a--waive-untilrecord to copy. The
command never changes the configuration. It exits1when it lists
anything, unless given--exit-zero, and--format jsonsuits scripts. See
the scanner command.check-opencloud-scanner fleet. It turns savedscanresult
documents into one summary of a fleet. Give it files, or directories that
it searches for*.json, and it keeps the newest report of each host. It
lists end-of-life releases and releases whose support ends soon. The
recorded version is placed in today's release schedule again, so a line
that closed after the report was written is listed too. It lists waivers
that let a failing check alert again within--windowdays (default
30), measured against today. It counts the failing findings that most
hosts share, and leaves out the ones no operator can change. Under missing
coverage it lists stale reports (--stale-after, default7days), failed
scans, checks the scans could not evaluate, and hosts named by--expect
or--inventorythat have no report. The output is text, Markdown, JSON,
or one self-contained HTML page that fetches nothing. It never scans,
stores nothing and applies no threshold, so it exits0whenever it
printed a summary. See
the scanner command.
Fixed
- The
.debinstall smoke test survives a mirror caught mid-sync. When
the Ubuntu or Debian mirror lists a dependency it no longer serves (a
404),packaging/tests/install-smoke.shrefreshes the package index and
tries the install once more before the release dry run fails.
What's Changed
Full Changelog: v1.30.2...v1.31.0
v1.30.2
check-opencloud-security 1.30.2
Changed
- Tests now cover code that no test reached before. The advisory refresh
scriptscripts/update_vulnerability_db.pyhas tests. They prove that it
writes new advisories and that--checkwrites nothing. If the feed is
down, the script keeps the file.scripts/verify_export.pyhas tests too. They
prove that it refuses edited bytes, the wrong key and a missing key. The scan
child process inwebapp/scan_process.pyhas tests for a rejected target, a
failed scan and a crash. A rejected target stays a rejection in the worker,
and a crash sends no exception text. The approval mode in
webapp/approval.pyhas tests that prove DNS never approves an address
target, and that a failed TXT lookup is a refusal.
tests/test_verify_remediation.pynow makes sure that every extra check and
hardening flag of a full scan verifies to the same answer, not only three of
them.
Documentation
- Clarified operator status, comparison results, monitoring instructions and
TLS explanations in English, German, Spanish and French. Corrected Spanish
forms of address and translated two overlooked deployment settings rows. - Expanded translation tests to cover copied English table descriptions,
duplicate catalogue keys, repeated placeholders, and formatting and HTML
escaping across every language, including messages on conditional pages.
Fixed
--waiver-warningandwaiver_days_leftno longer count a waiver that
only covers a flag OpenCloud hardcodes, such as
publicLinkExpirationEnforced. That flag never alerts, so the end of its
waiver changes nothing. Before this fix, such a waiver raised a WARNING.- The plugin output now says "1 day left" instead of "1 days left" in the
end-of-life warning, the lifecycle line and the waiver warning. If one
waiver covers several checks, the waiver warning now says that they
"alert again". - If two waivers end at the same moment, the waiver warning now names both.
Before this fix, it named only one waiver but listed the checks of both.
What's Changed
- chore: regenerate the Homebrew formula for the newest release by @github-actions[bot] in #115
- chore(release): 1.30.2 by @sowoi in #114
Full Changelog: v1.30.1...v1.30.2
v1.30.1
check-opencloud-security 1.30.1
Added
--waiver-warning DAYS(COS_WAIVER_WARNING, YAMLwaiver_warning)
sets a warning window for--waive-untilwaivers. If a waiver that hides
a failing check ends withinDAYSdays, an otherwise OK result becomes
WARNING. Before this, a waiver gave no lead time. The check was silent
until the deadline and alerted on the next run after it. The long output
also names the next waiver to end. The default0turns the warning off.- The
waiver_days_leftperformance value counts the days until that
waiver ends. With--waiver-warningit carries the window as its warning
range. Checkmk reports it under the same name, and Prometheus and OTLP as
opencloud_security_waiver_days_remaining. The webhook payload adds
waiver_days_left,waiver_warning_daysandwaiver_warning, and
contrib/prometheus/alerts.ymladds anOpenCloudWaiverExpiringrule. - The
coverage_inconclusiveandcoverage_not_checkedperformance values
put the coverage block on a graph. A graph now shows the day that checks
become unreadable. Checkmk uses the same names, and Prometheus and OTLP use
opencloud_security_coverage_inconclusive_totaland
opencloud_security_coverage_not_checked_total. The grade does not change.
Documentation
- Replaced vague and literal wording in the interface, scanner guides and
README. Aligned English, German, Spanish and French explanations and
corrected inconsistent forms of address. - Completed the remaining French guide translations while preserving commands,
technical values and section links. - Expanded wording checks to current repository documentation and Python
product strings, including phrases split across lines. Added regression
cases and a translation review checklist. Corrected inconsistent exemption
terminology and Spanish plural recognition in the glossary check. Recorded
reviewed plain-language alternatives so they no longer produce warnings.
What's Changed
- chore: regenerate the Homebrew formula for the newest release by @github-actions[bot] in #112
- chore(release): 1.30.1 by @sowoi in #113
Full Changelog: v1.30.0...v1.30.1
v1.30.0
check-opencloud-security 1.30.0
Documentation
-
Listed
tests/test_monitoring_export.pyin the test index, so the
scheduler-export tests can be found by purpose. -
Clarified German operator messages about wildcard DNS and temporary
application updates, and replaced the literal TLS introduction with a
description of the measured values. Added three wording regression cases. -
Clarified configuration-drift explanations in the English, German, Spanish
and French baseline guides. Older baselines lack fingerprints, so an absent
drift report does not establish that the configuration is unchanged.
Added regression cases for vague and anthropomorphic wording in all four
languages. Fixed four French guide links to the documentation index found
by the translation tests. -
Reworded literal German and Spanish translations in the baseline and scanner CLI
guides, including severity comparisons and missing measurements. Added
regression cases for the awkward phrases found during review.
Added
-
The setup wizard exports the scheduled check, not just the configuration.
check-opencloud-scanner configurenow offers to write the monitoring
configuration next to the file it saved, and--export-monitoring
(icinga,systemd,both,none) answers that question up front for a
provisioning script. It produces an Icinga 2Serviceobject, and a systemd
oneshotservice,dailytimer andCOS_environment file, each carrying
the thresholds, the release track and every other answer just given - so the
check that runs every day is the one that was configured rather than an
example adjusted from memory. Two rules shape the output: nothing is
installed (the files are written for review and the install commands are
printed, never run), and no credential is written into them - a webhook
URL or release token stays in the owner-only configuration file, which both
artefacts point at withvars.opencloud_configandCOS_CONFIG_FILE, and
the settings withheld are named rather than silently dropped. The generated
unit carries the same hardening directives as the one incontrib/systemd/,
asserted by a test so it cannot quietly become a weaker copy. -
check-opencloud-scanner diffcompares two results finding by finding.
A new--format side-by-sidestates both scans as two columns, one finding
per row, so a reader does not have to rebuild each side from a list of
changes;--all-findingsadds the findings that did not move. Every
comparison now reports per-finding severity movement - a~line and a
Failing by severity:tally - which the baseline's comparison of two sets
of names cannot express: a check that stayed open and moved fromhighto
criticalnever enters or leaves that set, and caps the rating a grade
lower.--categorynarrows the comparison to one area, taking a value
either from the finding categories (exposure,headers,transport,
advisory, ...) or from the change categories (instance,
referenceData,scanner,policy,unknown); an unknown value is
refused rather than silently showing nothing.--format jsoncarries the
same asfindingsandseverityTotals. A side that was never measured is
reported as such and never as a pass, and a waived finding is still counted. -
A finished scan downloads as a remediation bundle: only the work that is
left, with the configuration that closes it. The result page and
GET /api/scans/{uuid}/export/{format}gainedremediation-mdand
remediation-html. A bundle carries only the open, actionable findings- waived entries and the flags OpenCloud hardcodes are left out - each with
what the scanner observed, what it means and what to change, followed by the
nginx, Caddy, Traefik, Docker Compose and.envfragments that satisfy
them, rendered from the hardening catalogue's ownenv_fixand
header_fixentries. Every flavour is written out rather than one, each
naming which findings it covers and which belong in the other kind of file,
and a finding whose right value is a decision about the deployment is listed
as having no mechanical fix rather than given a placeholder to edit. The
grade, the passed checks and the advisory list stay in the full report:
repeating them here would bury the one thing the file is for.
- waived entries and the flags OpenCloud hardcodes are left out - each with
-
SARIF output now carries what a code-scanning dashboard needs to act on a
finding.--format sarifpreviously named a rule and a level and left the
rest to a reader's own research. Each rule now carries the hardening
catalogue's remediation sentence, the official documentation link
(helpUri), the catalogue entry that explains a per-path finding
(catalogueId-exposedforexposed:/opencloud.yaml), the setting
behind it, and thesecurity-severity,problem.severityandtags
properties GitHub code scanning sorts and filters alerts on. Each result
carries the severity, category, remediation and reference beside the host,
and apartialFingerprintsentry stable across runs, so a finding that has
been open for a month stays one alert with a history rather than a new one
every night. An advisory additionally namesfixedInand the release
window it covers (affectedRanges, e.g.>= 1.0.0, < 4.0.8), and the run
reports the rating, version and end-of-life state per scanned host. The web
application's own SARIF export gained the same properties and fingerprints,
keeping the two renderers in convention-sync as ADR 0026 requires. -
A scan result's
vulnerabilitiesentries name the release range they
apply to.affectedRanges(andintroduced) joinfixedIn, so a reader
can tell whether an older release was ever affected rather than only which
release ends the window.
Fixed
-
The French scanner CLI guide no longer ships the newly added comparison
sections in English. Itsdiffexplanation, severity view, side-by-side
output and category filtering are now translated, and regression tests catch
those copied-English phrases in future guide updates. -
The German operator area no longer leaves avoidable English labels in
place. Advisory status is shown as Sicherheitsmeldungen, update controls
as Aktualisierungen, and the audit section consistently names its log.
What's Changed
Full Changelog: v1.29.3...v1.30.0
v1.29.3
check-opencloud-security 1.29.3
Fixed
- Sloppy generated wording was removed from the English, German and French
documentation. Replaced vague promotional phrases and awkward literal
translations in the Kubernetes, scanner and reference-data guides, rebuilt
their frontend pages, and expanded the translation-quality tests with
regression cases for these patterns.
What's Changed
- chore: regenerate the Homebrew formula for the newest release by @github-actions[bot] in #109
- chore(release): 1.29.3 by @sowoi in #110
Full Changelog: v1.29.2...v1.29.3
v1.29.2
check-opencloud-security 1.29.2
Fixed
-
/llms.txtand/llms-full.txtdescribed an older version of the
service. They are the map an agent reads before deciding what this
service can do, and four of their facts had fallen behind the code:
/mcpwas described as six tools and six prompts where it registers seven
of each,compare_scanswas missing from the tool list in the long form,
the export formats omittedhtml, and the endpoint summary never mentioned
GET /api/scans/{uuid}/badge.svg. An agent that trusts the map would have
concluded the badge and the HTML export do not exist. All four now match
whatwebapp/mcp_server.py,wf.EXPORT_FORMATSandwebapp/openapi.py
actually serve. -
A page's
<lastmod>insitemap.xmlnow moves only when the page really
changed. The date came from the modification time of the template that
renders the page, and a checkout, a container build and an unpacked release
tarball all write every template at once - so every public page claimed to
have changed on release day, and a crawler told that everything changed
learns nothing from the file. Each public page's date is now recorded next
to a digest of its template inwebapp/data/page-revisions.json, and
scripts/update_page_revisions.pymoves a date only when that digest does.
A page the record has never seen, or one edited since it was written, still
falls back to the modification time rather than publishing a date that is
no longer true. CI checks the record with--check, as it does for the
generated documentation. -
The German, Spanish and French pages no longer drop names the English
text uses to say what this is. The translated "About" paragraph called the
plugin a generic monitoring plugin, so a reader of those pages never learned
it plugs into Nagios and Icinga, and it also lost the English sentence's
point that running it yourself has no rate limit or queue. The German and
French descriptions of the method page said "what the scanner checks"
without naming an OpenCloud instance, and the Spanish search summary for the
API page dropped OpenAPI, Arazzo and MCP - the three things somebody
searching for that page is searching for. All four strings now carry the
names again; the search index is rebuilt with them.
What's Changed
Full Changelog: v1.29.1...v1.29.2
v1.29.1
check-opencloud-security 1.29.1
Changed
-
The
--policydeployment gate is now covered by tests mutation testing
can run. Its behaviour was only ever exercised through the real CLI, which
runs the plugin as a subprocess, so mutation testing could delete the scan
document, the rating or the vulnerability list that_apply_policyis
handed - and drop the policy verdict from the webhook payload - without a
single test noticing. A violation that should fail a pipeline could have
stopped failing it silently.tests/test_policy_gate.pynow drives the same
gate in process and is listed in the mutmut selection; the five surviving
mutants it was written for are killed. -
A result list that no longer lines up with the checks that produced it is
now an error rather than a shorter report. Every place the scanner and the
plugin pair a list of checks with the results_run_allreturned for them -
the exposed paths, the protected endpoints, the debug endpoints and ports,
the demo accounts, and the per-host rows of thecheckmkandsummary
output formats - zipped the two without asserting they were the same length.
The lengths match by construction today, so nothing changes for any scan that
runs; what changes is the failure mode if a later edit breaks that pairing.
Silently dropping the tail would have meant a report that omits checks
without saying so, which reads as an instance that passed them. The one
pairing deliberately left lenient is the lifecycle page parser, where the two
lists come from somebody else's HTML and a tab without a panel must be
dropped rather than raise.
Fixed
- The browser test for the severity filter no longer drops its own press in
WebKit on CI. Pressing a counter hides most of the list and reveals the
status line above it, so the page it leaves behind is a different height
from the one that was pressed; the test read the new count back with a
single sample and pressed clear straight away, on a control that was
still settling. WebKit dropped that press rather than delivering it, the
filter stayed on, and the run failed counting a list nobody had asked for.
Each press is now waited out for the count it asked for before the next one
is aimed, which still fails - loudly - if a press is ever genuinely lost.
What's Changed
Full Changelog: v1.29.0...v1.29.1
v1.29.0
check-opencloud-security 1.29.0
Added
- A scan fingerprints the configuration it measured, so drift is visible
without the grade moving. A rewritten content security policy, a replaced
reverse proxy, public links that stopped requiring a password, a certificate
at a different issuer - none of that has to change a grade, and an operator
watching only the grade saw none of it. The result document now carries a
configurationblock: grouped digests for transport, headers, sharing,
authentication and proxy, plus one over all five. Digests only, never the
configuration - a policy, an issuer and a server banner go in and a hash
comes out, so the block is safe on a public page, in a webhook and in an
uploaded report. The plugin printsConfiguration fingerprint: 9e3c4428,
--baselinereportsNo new findings, but the configuration changed (headers),check-opencloud-scanner diffadds aconfigurationChanged
change, and the web application shows the groups under Has this deployment
changed?. Routine churn is deliberately excluded: a renewed certificate and
a proxy's new build number are not drift, and a group the two scans looked
at differently is reported as not comparable rather than as a change.
Nothing in it touches a rating, an exit code or an alert line. See
ADR 0073. --policyfails a deployment on explicit requirements, not on a grade.
-w/-cand--profilejudge an instance by its rating, which is the
wrong shape for a CI gate: a team that requires HTTPS enforcement and no
demo accounts cannot express that as a number. A policy file states it
directly -minimum_rating,required_hardeningsandforbidden(a
missing measure, a failed check or a vulnerability id) - and anything it
asks for that an instance does not meet ends the run CRITICAL. A policy
only ever makes a verdict worse, a waiver does not excuse a requirement,
and an unknown key or measure is a usage error rather than a rule that
quietly requires nothing.--format jsonand the webhook payload carry the
verdict underpolicy. See CI policy mode and
config/policy.example.yml.--format summaryreads a whole fleet in one table. Checking a dozen
instances printed a dozen result blocks written for a monitoring system,
which is a lot to read when the question is just "which of these needs me
today". The new format prints one aligned row per host instead - host,
grade, version, end-of-life state, how many advisories apply, and how much
moved since--baseline- followed by the same tally the Nagios output
starts with. Rows keep the order the hosts were given and the exit code is
unchanged, so it works from a cron job that mails its output. TheNEW
column distinguishes "no baseline given" (-) from "no new findings" (0),
and a host whose scan failed shows its Nagios status where the grade would
be. See Reading a fleet in one table.- The output says how much it could actually measure. A check that
passed and one that never ran left the same trace in the plugin's output -
nothing - so the plugin now prints aCoverage:line such as84 checks evaluated, 6 skipped, 2 indeterminate, 1 network-limited, and the webhook
payload and--format jsoncarry the same counts undercoverage. The web
application's What this scan did not measure section shows the same four
numbers.network_limitedis split out of the skipped and indeterminate
counts because a timeout or a missing route - DNSSEC, an external identity
provider, an optional endpoint - is the gap another vantage point might
close. Nothing in it changes a grade, an exit code or an alert line.
What's Changed
Full Changelog: v1.28.1...v1.29.0