arrow_backRetour aux issues
tmatens/compose-lint
#671
Débutant
Ouvrirarrow_forward
Débutant
Ouvrirarrow_forward
Débutant
Ouvrirarrow_forward
A fragment compose.override.yml skips the whole project and reports PASS, dropping a CRITICAL
ecoDébutant
bug
good first issue
descriptionDescription
An overlay that Compose merges without complaint makes compose-lint skip the entire project and report `PASS` at exit 0, dropping every finding in the base file. Three innocuous override shapes trigger it. Filing publicly per SECURITY.md, which puts false negatives in security rules in scope for normal issues.
## Reproduction
```yaml
# compose.yml
services:
web:
image: nginx
privileged: true
```
```yaml
# compose.override.yml
volumes:
data: {}
```
With the override present:
```console
$ compose-lint check compose.yml
compose.yml: Skipped: file appears to be a Compose fragment (no 'services:' key;
only top-level structural keys present). Fragments are typically merged via
`extends:` or `-f` overlays and have no services to lint on their own.
✓ PASS · threshold: high
$ echo $?
0
```
Delete the override and the same base file reports:
```console
4 CRITICAL CL-0002 Service runs in privileged mode...
✗ FAIL · 1 finding at or above high
$ echo $?
1
```
Docker Compose merges and deploys it either way (`docker compose config` exits 0, `privileged: true` intact).
## Scope
Any overlay with no `services:` key does it. All three verified against Docker Compose 5.4.0, all three deploy fine, all three produce `PASS` / exit 0:
| `compose.override.yml` | compose-lint | Compose |
|---|---|---|
| `volumes:\n data: {}` | PASS, exit 0 | deploys, `privileged: true` |
| `networks:\n n: {}` | PASS, exit 0 | deploys, `privileged: true` |
| `{}` | PASS, exit 0 | deploys, `privileged: true` |
## Why it matters
The shipped deployment model is a CI merge gate. Adding a two-byte `compose.override.yml` containing `{}` turns a failing gate green while changing nothing about what deploys. That is a silent false negative of the kind ADR-023 ranks worst, and it is trivially reachable rather than an edge case: an overlay carrying only `volumes:` or `networks:` is an ordinary thing to write.
The verdict is also actively wrong rather than merely absent. `✓ PASS` asserts the stack was graded and cleared. It was not graded at all.
## Cause
`load_merged` calls `load_document` per path. A fragment overlay raises `ComposeNotApplicableError` (ADR-013), which propagates out of the merge. The `check` loop's `except ComposeNotApplicableError` clause at `cli.py:~707` is written for the single-file case, where "this file is a fragment" correctly means "skip it", so it skips the whole project and reports it under the primary path.
Two defects fall out of that:
1. **The project is skipped when only the overlay is a fragment.** The base file has `services:` and is perfectly lintable. This is the security-relevant half.
2. **The message names the wrong file.** `compose.yml` is reported as the fragment when `compose.override.yml` is. Same class as #666, and deliberately not covered by #670, whose `except ComposeNotApplicableError: raise` is the correct ADR-013 behaviour. The fix belongs here, not there.
## Direction
Compose treats a fragment overlay as an ordinary document that happens to contribute only `volumes:` or `networks:`, and merges it. ADR-025 says compose-lint grades the configuration Compose runs, so the merge should do the same and lint the result.
ADR-013's "a fragment alone has no services to lint" reasoning is about a file linted *on its own*. It was never weighed against a fragment sitting in a merge set beside a base file that does have services, which is the case here.
Whatever the resolution, the current outcome is the one thing it must not stay: reporting `PASS` at exit 0 on a stack that was never graded.
Issues similaires
calkit/calkit
star53
Poids du dépôt moyen
VS Code extension should be robust to YAML parser errors
Seeing this error: ``` Failed to read calkit.yaml: YAMLParseError: A block sequence may not be used as an implicit map…
Python
bug
good first issue
fu351/Doberman-Core
star211
Poids du dépôt léger
dash: a manual Refresh control
The dashboard polls: `refreshStats()` (`src/doberman/dash/app.py:408`) every 5 s and `refreshPending()` (`:546`) every …
Python
enhancement
good first issue
fu351/Doberman-Core
star211
Poids du dépôt léger
dash: "Copy details" button on each pending-approval card
Each pending-approval card in the dashboard (`renderPending`, `src/doberman/dash/app.py:448-544`) shows the risk badge,…
Python
enhancement
good first issue