Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ RUN npm prune --omit=dev && \
FROM node:24-alpine

RUN apk update && \
apk add --no-cache python3 ruby curl bash jq unzip wget ca-certificates git github-cli file zip xz lz4 diffutils tree rsync openssh-server openssh-client cronie ripgrep && \
apk add --no-cache python3 ruby curl bash jq unzip wget ca-certificates git github-cli file zip xz lz4 diffutils tree rsync openssh-server openssh-client cronie ripgrep tzdata && \
ssh-keygen -A && \
adduser -S -G node -h /home/madz -s /bin/sh madz && \
mkdir -p /run/sshd /root/.cache /home/madz/.cache/madz/logs && \
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,12 @@ All configuration is controlled via environment variables in the `docker run` co
| `TUI_NAME` | `madz` | TUI identifier in banner |
| `TUI_CURSOR_CHAR` | `█` | Cursor character |

**Optional — Timezone:**

| Variable | Default | Description |
| -------- | ------- | ----------- |
| `TZ` | `UTC` | IANA timezone name (e.g., `America/Toronto`, `Europe/London`). The container ships with `tzdata` so any valid IANA timezone resolves. Set at runtime via `docker run -e TZ=...` or in `docker-compose.yml`. |

**Optional — Agent:**

| Variable | Default | Description |
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ services:
image: madz:latest
environment:
- NODE_ENV=development
- TZ=America/Toronto
ports:
- "2222:22"
volumes:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-08-25
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
## Context

The madz Docker image uses `node:24-alpine` as its base. Alpine images are minimal and do not include timezone data by default. The production stage installs ~20 system packages via `apk add` on line 20 of the Dockerfile. No timezone configuration exists anywhere in the Dockerfile or entrypoint.

## Goals / Non-Goals

**Goals:**
- Install `tzdata` in the Docker image so IANA timezone names resolve at runtime
- Container defaults to UTC — no hardcoded timezone
- Users override timezone via `TZ` environment variable at runtime

**Non-Goals:**
- Hardcoding a default timezone
- Adding timezone-aware tests
- Changing the base image or entrypoint
- Adding timezone configuration files

## Decisions

1. **Append `tzdata` to existing `apk add` line** — Minimal change, single line in Dockerfile. No new layers, no new instructions.
- *Alternative:* Separate `RUN apk add tzdata` — creates an extra layer, unnecessary.
- *Rationale:* Single layer, no image size penalty beyond the package itself.

2. **No `ENV TZ` in Dockerfile** — Let the container default to UTC.
- *Alternative:* Set `ENV TZ=America/Toronto` — forces a timezone on all users.
- *Rationale:* UTC is the Linux standard. Users who need a specific timezone pass `-e TZ` at runtime.

3. **No entrypoint changes** — `docker-entrypoint.sh` does not set or override `TZ`.
- *Verification:* Confirmed by reading the file — no TZ references found.

## Risks / Trade-offs

- **Image size** — `tzdata` adds ~1.5MB. Mitigation: negligible compared to the total image size (~500MB+ with node_modules).
- **No default timezone** — Users who don't set `TZ` get UTC. Mitigation: this is the expected Linux behavior and the safest default.
- **No automated tests** — Docker image behavior verified manually. Mitigation: sufficient for a single-line change; adding Docker tests is out of scope.

## Migration Plan

1. Merge PR to `main`
2. Rebuild Docker images via `npm run docker:release:all`
3. Verify with `docker run --rm <image> date` (UTC) and `docker run --rm -e TZ=America/Toronto <image> date` (Eastern)
4. No rollback needed — removing `tzdata` from the Dockerfile is the rollback if needed

## Open Questions

None. This is a single-line change with no ambiguity.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
## Why

The madz Docker container uses a minimal Alpine base image that ships without timezone data (`tzdata`). Without it, the container defaults to UTC and cannot resolve IANA timezone names (e.g., `America/Toronto`) when the `TZ` environment variable is set at runtime. This causes incorrect timestamps in logs, misaligned cron schedules, and confusion for users in non-UTC timezones.

## What Changes

- Add `tzdata` to the Alpine package installation in the Dockerfile
- Container defaults to UTC (no hardcoded `ENV TZ`)
- Users can override timezone at runtime via `docker run -e TZ=<IANA_name>`

## Capabilities

### New Capabilities
- **docker-tzdata**: Timezone data support in the Docker container via the `tzdata` Alpine package

### Modified Capabilities
<!-- None — no existing spec-level requirements are changing -->

## Impact

- **Dockerfile** — Package installation line modified (line 20)
- **Image size** — ~1.5MB increase (negligible)
- **Runtime behavior** — Timezone resolution now works when `TZ` is set
- **No code changes** — Application code, entrypoint, and config remain unchanged

## Non-goals

- Hardcoding a default timezone in the Dockerfile
- Adding timezone-aware tests (manual verification is sufficient)
- Changing the Docker base image
- Adding timezone configuration files or symlinks
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# dockerfile-dependencies Spec Delta

## ADDED Requirements

### Requirement: tzdata must be installed in the container image

The Dockerfile SHALL include `tzdata` in the `apk add --no-cache` command in the runtime stage, ensuring timezone data is present in every built container image.

#### Scenario: tzdata is in the Dockerfile package list
- **WHEN** the Dockerfile runtime stage is parsed
- **THEN** `tzdata` appears in the `apk add --no-cache` command

#### Scenario: tzdata is available in the container
- **WHEN** the container is built and started
- **THEN** `tzdata` is installed and IANA timezone names (e.g., `America/Toronto`) resolve correctly

### Requirement: Timezone override via environment variable

The Dockerfile SHALL NOT hardcode a default timezone. The container defaults to UTC, and users may override the timezone by setting the `TZ` environment variable at runtime.

#### Scenario: Container defaults to UTC
- **WHEN** the container is started without `TZ` set
- **THEN** the system timezone is UTC

#### Scenario: Timezone override at runtime
- **WHEN** the container is started with `TZ=America/Toronto`
- **THEN** the system timezone reflects Eastern Time (EST/EDT)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Tasks

- [x] 1. Read the Dockerfile and identify the `apk add` line in the runtime stage (line 20)
- [x] 2. Append `tzdata` to the existing `apk add --no-cache` command on line 20
- [x] 3. Verify no `ENV TZ` is set in the Dockerfile (confirm UTC default behavior)
- [x] 4. Read `docker-entrypoint.sh` and confirm it does not set or override `TZ`
- [x] 5. Verify the Dockerfile builds successfully (dry-run or full build)
- [x] 6. Verify timezone resolution works: `docker run --rm <image> date` shows UTC, `docker run --rm -e TZ=America/Toronto <image> date` shows Eastern Time
- [x] 7. Run `npm run test` and `npm run coverage` to confirm no regressions (no JS code changes — coverage N/A)
24 changes: 24 additions & 0 deletions openspec/specs/dockerfile-dependencies/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,27 @@ The Dockerfile SHALL include `gh` in the `apk add --no-cache` command in the run
- **WHEN** the container is built and started
- **THEN** `gh --version` executes successfully without "command not found"

### Requirement: tzdata must be installed in the container image

The Dockerfile SHALL include `tzdata` in the `apk add --no-cache` command in the runtime stage, ensuring timezone data is present in every built container image.

#### Scenario: tzdata is in the Dockerfile package list
- **WHEN** the Dockerfile runtime stage is parsed
- **THEN** `tzdata` appears in the `apk add --no-cache` command

#### Scenario: tzdata is available in the container
- **WHEN** the container is built and started
- **THEN** `tzdata` is installed and IANA timezone names (e.g., `America/Toronto`) resolve correctly

### Requirement: Timezone override via environment variable

The Dockerfile SHALL NOT hardcode a default timezone. The container defaults to UTC, and users may override the timezone by setting the `TZ` environment variable at runtime.

#### Scenario: Container defaults to UTC
- **WHEN** the container is started without `TZ` set
- **THEN** the system timezone is UTC

#### Scenario: Timezone override at runtime
- **WHEN** the container is started with `TZ=America/Toronto`
- **THEN** the system timezone reflects Eastern Time (EST/EDT)