Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ceb78b00c | ||
|
|
f79a175021 | ||
|
|
552d3dd289 |
@@ -14,7 +14,7 @@ RUN apk add --no-cache \
|
||||
coreutils findutils diffutils gawk grep sed \
|
||||
file less patch tree \
|
||||
curl wget \
|
||||
jq \
|
||||
jq yamllint \
|
||||
bind-tools iputils-ping netcat-openbsd socat rsync \
|
||||
git git-lfs openssh-client-default \
|
||||
ripgrep fd \
|
||||
|
||||
@@ -24,6 +24,7 @@ Base: `node:22-alpine` · ~400 MB uncompressed (`kubectl` and `helm` are about
|
||||
| Text & search | `jq`, `yq`, `ripgrep` (`rg`), `fd`, `less`, `file`, `patch`, `tree` |
|
||||
| Network | `curl`, `wget`, `dig`/`nslookup`/`host` (bind-tools), `nc`, `socat`, `rsync`, `ping`, `openssl` |
|
||||
| Kubernetes | `helm`, `kubectl` |
|
||||
| Linting | `yamllint` |
|
||||
| Source control | `git`, `git-lfs`, `ssh`/`scp`/`sftp` |
|
||||
| Archives | `tar`, `gzip`, `xz`, `zip`, `unzip` |
|
||||
| System | `ps`/`top`/`free` (procps-ng), `make`, `su-exec`, `tini`, `tzdata`, `ca-certificates` |
|
||||
@@ -35,6 +36,28 @@ is pinned. Run `<tool> --version` in the image for what a given tag actually shi
|
||||
`yq` comes from upstream releases because Alpine does not package it; everything
|
||||
else is an Alpine package.
|
||||
|
||||
### Manifest validation
|
||||
|
||||
`yamllint` backs the `yamllint` MCP server in `50W/kube-manifests`, which pairs it
|
||||
with `kubectl` for Kubernetes manifests:
|
||||
|
||||
```sh
|
||||
yamllint -f parsable -d relaxed manifest.yaml
|
||||
kubectl create --dry-run=client --validate=strict -f manifest.yaml
|
||||
```
|
||||
|
||||
Worth knowing what that second command does **not** catch. Client-side validation
|
||||
rejects malformed YAML, a document that is not a Kubernetes object, and a missing
|
||||
`apiVersion`/`kind` — but it does **not** reject an unknown or renamed field on a CRD
|
||||
(Flux's `HelmRelease` sets `x-kubernetes-preserve-unknown-fields`), nor a wrong scalar
|
||||
type. Only `--dry-run=server` catches those, and server-side dry-run is authorized as
|
||||
a **write**, so it needs `create`/`patch` RBAC that this image's consumers deliberately
|
||||
do not have.
|
||||
|
||||
Client-side validation needs no RBAC at all — it only fetches the OpenAPI schema,
|
||||
which every authenticated identity may do — but it does need to reach the API server.
|
||||
With no API access it fails closed on valid manifests (`failed to download openapi`).
|
||||
|
||||
## Environment
|
||||
|
||||
| Variable | Value | Why |
|
||||
|
||||
@@ -42,8 +42,8 @@ gnu() {
|
||||
}
|
||||
|
||||
echo "-- present on PATH"
|
||||
for t in bash sh curl wget jq yq helm kubectl git git-lfs ssh scp dig nslookup host \
|
||||
nc socat rsync ping rg fd tar gzip xz zip unzip less file patch tree make \
|
||||
for t in bash sh curl wget jq yq yamllint helm kubectl git git-lfs ssh scp dig nslookup \
|
||||
host nc socat rsync ping rg fd tar gzip xz zip unzip less file patch tree make \
|
||||
ps top free tini su-exec node npm npx openssl base64 env xargs; do
|
||||
have "$t"
|
||||
done
|
||||
@@ -63,6 +63,8 @@ works 'fd finds' bash -c 'fd -1 . /tmp >/dev/null'
|
||||
works 'dig runs' dig -v
|
||||
works 'openssl runs' openssl version
|
||||
works 'node runs' node -e 'process.exit(0)'
|
||||
works 'yamllint flags bad' bash -c '! printf "a: [\n" | yamllint - >/dev/null 2>&1'
|
||||
works 'yamllint passes ok' bash -c 'printf "a: 1\n" | yamllint -d relaxed -'
|
||||
|
||||
echo "-- deployment contract"
|
||||
[ "$(id -u)" = 1000 ] && ok 'runs as uid 1000' || bad "runs as uid $(id -u), want 1000"
|
||||
|
||||
Reference in New Issue
Block a user