# Lsst Sqre Squareone Docker Version Validation

> Docker Version Validation

- Skill: `tomevault-io/lsst-sqre-squareone-docker-version-validation` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/lsst-sqre-squareone-docker-version-validation`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/lsst-sqre-squareone-docker-version-validation/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/lsst-sqre-squareone-docker-version-validation

---


# Docker Version Validation

This skill ensures that version declarations in Dockerfiles stay synchronized with their corresponding `package.json` files. The validation system automatically runs on pre-commit hooks and in CI, preventing version drift between Docker builds and package configurations.

## When to Use This Skill

Use this skill when:

- **Updating Node.js versions** in Dockerfile base images
- **Updating pnpm versions** via `corepack prepare`
- **Updating Turbo versions** in Docker build commands
- **Creating new Dockerfiles** that use versioned tools
- **Troubleshooting version mismatch errors** from validation failures
- **Understanding why a commit was rejected** due to version inconsistencies

## What Gets Validated

The validation system checks three critical version synchronization points:

### 1. Node.js Version

**Dockerfile location:**
```dockerfile
FROM node:22.21.1-alpine AS base
```

**package.json source:**
```json
{
  "engines": {
    "node": "^22.21.1"
  }
}
```

**Validation rule:** Major.minor versions must match (patch differences allowed)
- ✅ Docker `22.21.1` matches package.json `^22.21.1`
- ✅ Docker `22.21.2` matches package.json `^22.21.1` (patch difference OK)
- ❌ Docker `22.22.0` does NOT match package.json `^22.21.1` (minor mismatch)

### 2. pnpm Version

**Dockerfile location:**
```dockerfile
RUN corepack prepare pnpm@10.20.0 --activate
```

**package.json source:**
```json
{
  "packageManager": "pnpm@10.20.0+sha512..."
}
```

**Validation rule:** Exact version match required
- ✅ Docker `10.20.0` matches package.json `pnpm@10.20.0+sha512...`
- ❌ Docker `10.20.1` does NOT match package.json `pnpm@10.20.0+sha512...`

### 3. Turbo Version

**Dockerfile location:**
```dockerfile
RUN pnpm dlx turbo@2.6.0 prune --scope=squareone --docker
```

**package.json source:**
```json
{
  "devDependencies": {
    "turbo": "2.6.0"
  }
}
```

**Validation rule:** Exact version match required
- ✅ Docker `2.6.0` matches package.json `2.6.0`
- ❌ Docker `2.6.1` does NOT match package.json `2.6.0`

## How Validation Works

### Automatic Validation Points

The validation runs automatically at three integration points:

**1. Pre-commit Hook (via lint-staged)**
```javascript
// .lintstagedrc.mjs
export default {
  '**/Dockerfile*': ['node scripts/validate-docker-versions.js'],
};
```

- **Triggers:** When you stage any Dockerfile for commit
- **Behavior:** Validates before commit completes
- **Outcome:** Blocks commit if versions mismatch

**2. CI Pipeline (GitHub Actions)**
```yaml
# .github/workflows/ci.yaml
- name: Validate Docker versions
  run: node scripts/validate-docker-versions.js
```

- **Triggers:** On every push and pull request
- **Behavior:** Runs early in test job (before formatting, linting, building)
- **Outcome:** Fails CI if versions mismatch

**3. Manual Validation**
```bash
pnpm validate-docker
```

- **Triggers:** On-demand when you run the command
- **Behavior:** Scans all Dockerfiles in repository
- **Outcome:** Exits with code 1 if mismatches found

### Discovery and Mapping

The validation script automatically:

1. **Discovers all Dockerfiles** in the repository (excluding `node_modules`, `.git`, etc.)
2. **Maps each Dockerfile** to its nearest `package.json` (walks up directory tree)
3. **Extracts versions** from both files using regex patterns
4. **Compares versions** according to validation rules
5. **Reports results** with clear error messages

## Running Manual Validation

### Check All Dockerfiles

```bash
pnpm validate-docker
```

**Example output (all valid):**
```
Docker Version Validator
Checking Dockerfiles in: /Users/you/squareone

Found 1 Dockerfile(s) to validate

Validating: apps/squareone/Dockerfile
Against: apps/squareone/package.json
  ✓ Node.js: 22.21.1 matches 22.21.1 (from constraint: ^22.21.1)
  ✓ pnpm: 10.20.0 matches package.json
  ✓ Turbo: 2.6.0 matches package.json

Summary:
  Dockerfiles validated: 1
  ✓ All versions match!
```

**Example output (version mismatch):**
```
Docker Version Validator
Checking Dockerfiles in: /Users/you/squareone

Found 1 Dockerfile(s) to validate

Validating: apps/squareone/Dockerfile
Against: apps/squareone/package.json
  ✓ Node.js: 22.21.1 matches 22.21.1 (from constraint: ^22.21.1)
  ✗ pnpm version mismatch:
    Dockerfile: 10.20.1
    package.json: 10.20.0
  ✓ Turbo: 2.6.0 matches package.json

Summary:
  Dockerfiles validated: 1
  ✗ Found 1 version mismatch(es)

To fix:
  1. Update the Dockerfile to match package.json versions, or
  2. Update package.json to match Dockerfile versions

Validation rules:
  - Node.js: Major.minor must match (patch differences allowed)
  - pnpm: Exact version match required
  - Turbo: Exact version match required
```

## Updating Versions Correctly

Follow this workflow when updating tool versions to keep everything synchronized:

### Option 1: Update package.json First (Recommended)

1. **Update package.json:**
   ```json
   {
     "packageManager": "pnpm@10.21.0+sha512...",
     "devDependencies": {
       "turbo": "2.7.0"
     },
     "engines": {
       "node": "^22.22.0"
     }
   }
   ```

2. **Update Dockerfile to match:**
   ```dockerfile
   FROM node:22.22.0-alpine AS base
   RUN corepack prepare pnpm@10.21.0 --activate
   RUN pnpm dlx turbo@2.7.0 prune --scope=squareone --docker
   ```

3. **Validate changes:**
   ```bash
   pnpm validate-docker
   ```

4. **Stage and commit:**
   ```bash
   git add package.json apps/squareone/Dockerfile
   git commit -m "Update Node.js to 22.22.0, pnpm to 10.21.0, turbo to 2.7.0"
   ```

### Option 2: Update Dockerfile First

1. **Update Dockerfile:**
   ```dockerfile
   FROM node:22.22.0-alpine AS base
   RUN corepack prepare pnpm@10.21.0 --activate
   RUN pnpm dlx turbo@2.7.0 prune --scope=squareone --docker
   ```

2. **Update package.json to match:**
   ```json
   {
     "packageManager": "pnpm@10.21.0+sha512...",
     "devDependencies": {
       "turbo": "2.7.0"
     },
     "engines": {
       "node": "^22.22.0"
     }
   }
   ```

3. **Validate and commit** (same as Option 1)

### Updating Only One Version

If you're updating just Node.js, pnpm, or Turbo (not all three):

1. **Update both files** (package.json and Dockerfile) for that specific version
2. **Run validation** to confirm: `pnpm validate-docker`
3. **Commit both changes together**

**Example: Update only pnpm version**
```bash
# Edit package.json: packageManager: "pnpm@10.21.0+sha512..."
# Edit Dockerfile: RUN corepack prepare pnpm@10.21.0 --activate
pnpm validate-docker
git add package.json apps/squareone/Dockerfile
git commit -m "Update pnpm to 10.21.0"
```

## Troubleshooting

### Pre-commit Hook Rejected My Commit

**Problem:** You staged a Dockerfile change but the commit was blocked:
```
✗ pnpm version mismatch:
  Dockerfile: 10.20.1
  package.json: 10.20.0
```

**Solution:**
1. Fix the version mismatch in either Dockerfile or package.json
2. Stage the corrected file: `git add <file>`
3. Try committing again

**Quick fix:**
```bash
# Option A: Update Dockerfile to match package.json
# Edit apps/squareone/Dockerfile manually
git add apps/squareone/Dockerfile
git commit

# Option B: Update package.json to match Dockerfile
# Edit package.json manually
git add package.json
git commit
```

### CI Pipeline Failing on Version Validation

**Problem:** CI fails early with "Validate Docker versions" step

**Solution:**
1. Check the CI logs for the specific version mismatch
2. Pull the latest changes if working on a branch
3. Update versions locally to match
4. Push the fix

**Example fix:**
```bash
# Check what's wrong
pnpm validate-docker

# Fix the mismatch (edit files)

# Validate locally
pnpm validate-docker

# Commit and push
git add package.json apps/squareone/Dockerfile
git commit -m "Fix Docker version mismatch"
git push
```

### Version Found in Only One File

**Warning:** `⚠ pnpm version found in only one file (Docker: 10.20.0, package.json: none)`

**Explanation:** This is a warning (not an error). The validation found a version declaration in the Dockerfile but not in package.json, or vice versa.

**Common causes:**
- New Dockerfile added without updating package.json
- Version removed from package.json but still in Dockerfile
- Parsing failed to find the version (incorrect format)

**Solution:**
1. Ensure both files declare the version
2. Check that the format matches the expected pattern (see "What Gets Validated" above)

### Validation Script Not Finding Versions

**Problem:** Validation reports versions as "not found" even though they exist

**Cause:** The version format in the Dockerfile doesn't match the expected regex pattern

**Dockerfile patterns expected:**
```dockerfile
# Node.js
FROM node:22.21.1-alpine

# pnpm
RUN corepack prepare pnpm@10.20.0 --activate

# Turbo
RUN pnpm dlx turbo@2.6.0 prune ...
# OR
RUN pnpx turbo@2.6.0 prune ...
```

**Solution:** Ensure your Dockerfile uses these exact patterns. If using a different format, the validation script may need updates.

## Technical Details

### Validation Script

**Location:** `scripts/validate-docker-versions.js`

**Key functions:**
- `findDockerfiles(dir)` - Recursively finds all Dockerfiles
- `findNearestPackageJson(filePath)` - Walks up directory tree to find package.json
- `parseDockerfile(path)` - Extracts versions using regex patterns
- `parsePackageJson(path)` - Reads and extracts versions from JSON
- `compareVersions(v1, v2, matchType)` - Compares versions according to rules
- `validateDockerfile(path, rootDir)` - Main validation logic

**Exit codes:**
- `0` - All versions match
- `1` - Version mismatches found
- `2` - Validation error (missing files, parse errors)

### Validation Rules Implementation

**Major.minor matching (Node.js):**
```javascript
function compareVersions(v1, v2, matchType = 'exact') {
  const cleanV1 = v1.replace(/^[\^~>=<]+/, '');
  const cleanV2 = v2.replace(/^[\^~>=<]+/, '');

  if (matchType === 'major.minor') {
    const [major1, minor1] = cleanV1.split('.');
    const [major2, minor2] = cleanV2.split('.');
    return major1 === major2 && minor1 === minor2;
  }

  return cleanV1 === cleanV2;
}
```

### Integration Points

**Pre-commit (lint-staged):**
- Configured in `.lintstagedrc.mjs`
- Runs only when `**/Dockerfile*` files are staged
- Blocks commit on validation failure

**CI (GitHub Actions):**
- Configured in `.github/workflows/ci.yaml`
- Runs in `test` job after installing packages
- Fails CI build on validation error

**Manual:**
- Accessible via `pnpm validate-docker`
- Runs full validation across all Dockerfiles
- Useful for debugging and development

## Best Practices

### When Creating New Dockerfiles

1. **Copy version patterns** from existing Dockerfiles (e.g., `apps/squareone/Dockerfile`)
2. **Use the same tool versions** as package.json from the start
3. **Run validation** before first commit: `pnpm validate-docker`
4. **Commit both files** (Dockerfile + package.json) together

### When Updating Versions

1. **Update package.json first** (single source of truth)
2. **Update all Dockerfiles** that use the version
3. **Run validation** locally before committing
4. **Group related version updates** in single commits

### During Code Review

1. **Check for version updates** in both Dockerfile and package.json
2. **Verify validation passed** in CI
3. **Ask about version choices** if major/minor updates
4. **Ensure changeset exists** for version changes

## Related Documentation

- **Turborepo workflow:** `.claude/skills/turborepo-workflow/` - Build and caching patterns
- **Remote cache docs:** `docs/dev/remote-cache.rst` - Turborepo remote caching infrastructure
- **Docker builds:** `.github/workflows/build-squareone.yaml` - Docker build workflow
- **CLAUDE.md:** General development commands and patterns

## Questions?

- **What versions should I use?** Check `package.json` for the current versions
- **Why exact match for pnpm/turbo but not Node?** Patch versions of Node are typically compatible, but pnpm/turbo can have breaking changes
- **Can I disable validation?** Not recommended, but you can remove the pre-commit hook or CI step
- **What if I need different versions?** Update package.json to reflect the desired state, then update Dockerfiles to match

---
> Converted and distributed by [TomeVault](https://tomevault.io/claim/lsst-sqre) — claim your Tome and manage your conversions.
<!-- tomevault:4.0:skill_md:2026-04-13 -->

