# Exercise 1: Harden a Dockerfile and Its Run Command

## The Starting Point

```dockerfile
FROM node:latest
ENV DB_PASSWORD=Sup3rS3cret!
ADD https://example.com/tools/healthcheck.sh /usr/local/bin/healthcheck.sh
COPY . /app
WORKDIR /app
RUN npm install
RUN chmod 777 -R /app
EXPOSE 3000
CMD npm start
```

```bash
docker run -d --privileged -v /var/run/docker.sock:/var/run/docker.sock \
  -p 3000:3000 --name api my-api
```

The app is an Express API that: listens on 3000, writes uploads to `/app/uploads`, reads `DB_PASSWORD` at startup, and needs no other host access.

## Deliverables

1. **Findings table**: list every security problem in the Dockerfile and the run command (aim for at least 12), each with the risk and the section of `docker_container_security_theory.md` (or `06-multi_stage_builds/`) that addresses it.
2. **Hardened Dockerfile**: multi-stage, pinned base (tag + digest placeholder), production dependencies only, non-root user, correct ownership/permissions for the uploads directory, exec-form CMD, no secrets, a `HEALTHCHECK` that doesn't download anything at build time.
3. **Hardened run command** (or Compose service): user, read-only root fs with the right writable mounts, capability drops, no-new-privileges, resource limits, secret injection for `DB_PASSWORD`.
4. **CI gates**: the commands/steps you add to the pipeline (scan, SBOM, sign) and the failure policy.
5. **Explain the two worst issues** in a short paragraph each: why `--privileged` + docker.sock together are equivalent to giving the container root on the host.

## Requirements Checklist

- [ ] Findings include: `latest` tag, secret in `ENV`, `ADD` from a URL (unverified remote content), `COPY . .` before install (cache + context leakage, no `.dockerignore`), dev dependencies shipped, `chmod 777`, running as root, shell-form CMD (signals not forwarded to node), `--privileged`, Docker socket mount, no resource limits, writable root fs, no health check.
- [ ] Hardened Dockerfile uses a build stage + slim/distroless runtime, `npm ci --omit=dev`, `USER` non-root, uploads dir owned by that user (not 777), `CMD ["node", "server.js"]`.
- [ ] Run command includes `--read-only` with a volume/tmpfs for uploads and `/tmp`, `--cap-drop ALL`, `--security-opt no-new-privileges`, `--memory`/`--cpus`/`--pids-limit`, and the password via a secret (file) instead of an image `ENV`.
- [ ] CI runs an image scanner with a severity threshold, generates an SBOM and signs the image; deploy verifies the signature.
- [ ] The explanation shows that the Docker socket lets the container start a new privileged container mounting the host's `/`, and `--privileged` grants all capabilities and device access.
