CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl-labs/devops-essentials

DevOps essentials — Dockerfile best practices, CI/CD patterns, deployment configuration, and container security

89

1.21x
Quality

87%

Does it follow best practices?

Impact

100%

1.21x

Average score across 3 eval scenarios

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

criteria.jsonevals/scenario-2/

{
  "context": "Tests whether the agent proactively follows Dockerfile best practices when containerizing a Node.js API. The task only asks for a Dockerfile — it never mentions multi-stage builds, non-root users, layer ordering, or HEALTHCHECK. A production-ready Dockerfile should have all of these.",
  "type": "weighted_checklist",
  "checklist": [
    {
      "name": "Multi-stage build",
      "description": "Dockerfile uses at least two stages: a build stage that installs all dependencies and compiles TypeScript, and a production/runtime stage that contains only the compiled output and production dependencies. The production stage must not contain TypeScript compiler, dev dependencies, or source .ts files.",
      "max_score": 15
    },
    {
      "name": "Non-root user",
      "description": "Production stage creates a non-root user (via adduser, addgroup, useradd, or equivalent) and includes a USER instruction to switch to that user. The container must not run as root.",
      "max_score": 15
    },
    {
      "name": ".dockerignore file created",
      "description": "A .dockerignore file is created that excludes at minimum node_modules, .git, and .env files. Additional exclusions like dist, coverage, .vscode are good but not required.",
      "max_score": 12
    },
    {
      "name": "Cache-efficient layer ordering",
      "description": "In the build stage, package.json and package-lock.json are copied BEFORE the rest of the source code, and npm install/npm ci runs between these two COPY steps. This ensures source code changes don't invalidate the dependency cache.",
      "max_score": 12
    },
    {
      "name": "HEALTHCHECK instruction",
      "description": "Dockerfile includes a HEALTHCHECK instruction that probes the /health endpoint (or similar) with appropriate interval, timeout, and retries settings. Uses wget, curl, or a custom health check script.",
      "max_score": 12
    },
    {
      "name": "Specific base image tag",
      "description": "FROM instructions use specific version tags (e.g., node:20-alpine, node:20-slim, node:22-alpine) rather than :latest or untagged node image.",
      "max_score": 8
    },
    {
      "name": "Alpine or slim base image",
      "description": "Uses a minimal base image variant (alpine or slim) rather than the full Debian-based node image to reduce image size and attack surface.",
      "max_score": 6
    },
    {
      "name": "npm ci instead of npm install",
      "description": "Uses npm ci (clean install) rather than npm install for reproducible, deterministic builds from the lockfile.",
      "max_score": 5
    },
    {
      "name": "NODE_ENV set to production",
      "description": "NODE_ENV is set to 'production' in the production stage via ENV instruction.",
      "max_score": 5
    },
    {
      "name": "EXPOSE instruction present",
      "description": "Dockerfile includes an EXPOSE instruction documenting the port the application listens on.",
      "max_score": 5
    },
    {
      "name": "WORKDIR set",
      "description": "Both stages use WORKDIR to set a working directory rather than running commands in the root filesystem.",
      "max_score": 5
    }
  ]
}

evals

tile.json