From 6c3c49736a7feb94555544496892ca77cb8310e5 Mon Sep 17 00:00:00 2001 From: jcardozo-eth <131674798+jcardozo-eth@users.noreply.github.com> Date: Thu, 9 Jul 2026 15:59:16 +0200 Subject: [PATCH 1/6] docs(changelog): reflow the 1.0.0 entries to one line each --- CHANGELOG.md | 86 ++++++++++++++-------------------------------------- 1 file changed, 22 insertions(+), 64 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0986e6f..c5c10b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,85 +9,43 @@ module follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [1.0.0] - 2026-07-09 -The initial release: a rootless GitLab Runner host — runner config, the rootless-Docker -pieces it depends on, packages, and secrets — managed as reviewable Puppet code, applied -standalone or from a Puppet fleet. Targets Ubuntu 22.04 with Puppet 8/OpenVox 8. +The initial release: a rootless GitLab Runner host — runner config, the rootless-Docker pieces it depends on, packages, and secrets — managed as reviewable Puppet code, applied standalone or from a Puppet fleet. Targets Ubuntu 22.04 with Puppet 8/OpenVox 8. ### Added #### Runner configuration -- Manage the entire GitLab Runner `config.toml` file from Hiera data — global settings and any - number of runners on a single host, all from one node file. The module is never edited to - onboard a host or team; host data drives it. -- Declare values shared by every runner once (`url`, `image`, `executor`, …) and override - per runner where needed. -- Support the Docker executor options runners actually use — images, volumes, - environment, per-runner caching, and image/pull-policy allowlists — so the module stays - out of the way of runner tuning. -- Changes converge continuously: once a data change is applied, the runner adopts the new - configuration on its own within seconds — no service restarts to arrange. -- Removing a runner is a data change too: drop its entry from Hiera and the next apply - renders it out of the config, so the host stops offering it (delete the record on the - GitLab side separately). +- Manage the entire GitLab Runner `config.toml` file from Hiera data — global settings and any number of runners on a single host, all from one node file. The module is never edited to onboard a host or team; host data drives it. +- Declare values shared by every runner once (`url`, `image`, `executor`, …) and override per runner where needed. +- Support the Docker executor options runners actually use — images, volumes, environment, per-runner caching, and image/pull-policy allowlists — so the module stays out of the way of runner tuning. +- Changes converge continuously: once a data change is applied, the runner adopts the new configuration on its own within seconds — no service restarts to arrange. +- Removing a runner is a data change too: drop its entry from Hiera and the next apply renders it out of the config, so the host stops offering it (delete the record on the GitLab side separately). #### Rootless Docker -- Make the rootless-Docker `no-detach-netns` fix permanent, so routine package upgrades on - Ubuntu 22.04 stop silently breaking rootless container networking. -- A toggle lets the module build the runner user's rootless Docker daemon from scratch — so a - fresh host becomes a working runner from the module alone — or, left off, treats an existing - daemon as a prerequisite. When it builds the daemon, a preflight checks the prerequisites first - and stops with a clear message if any is missing. +- Make the rootless-Docker `no-detach-netns` fix permanent, so routine package upgrades on Ubuntu 22.04 stop silently breaking rootless container networking. +- A toggle lets the module build the runner user's rootless Docker daemon from scratch — so a fresh host becomes a working runner from the module alone — or, left off, treats an existing daemon as a prerequisite. When it builds the daemon, a preflight checks the prerequisites first and stops with a clear message if any is missing. #### Secrets -- Keep runner tokens out of git: they live in an off-repository store on the host and are - referenced by name, so neither the control repository nor the rendered configuration ever - contains a secret. -- Deploy pre-created GitLab runner tokens — the module never talks to the GitLab API, - so an apply never depends on GitLab being reachable, and a host only ever holds its own - runner token. -- Fail loudly on an unrecognized runner setting, and — when a secret store is present — on - any runner whose token can't be resolved, so a typo (even in a security allowlist) stops - the apply instead of silently bringing up a misconfigured runner. Without a store - (dry-runs, CI validation), tokens render blank by design, so the configuration still - compiles anywhere. +- Keep runner tokens out of git: they live in an off-repository store on the host and are referenced by name, so neither the control repository nor the rendered configuration ever contains a secret. +- Deploy pre-created GitLab runner tokens — the module never talks to the GitLab API, so an apply never depends on GitLab being reachable, and a host only ever holds its own runner token. +- Fail loudly on an unrecognized runner setting, and — when a secret store is present — on any runner whose token can't be resolved, so a typo (even in a security allowlist) stops the apply instead of silently bringing up a misconfigured runner. Without a store (dry-runs, CI validation), tokens render blank by design, so the configuration still compiles anywhere. #### Flexible host ownership -- Opt-in toggles decide what the module owns on each host: the runner user and the - rootless prerequisites it needs, the Docker and GitLab Runner apt repositories (so stock - Ubuntu just works), the package set, and the runner service itself. -- Any toggle left off keeps the module hands-off that concern — safe to run alongside - another configuration-management system that already owns the user, the daemon, or the - repositories. -- Coexist with a central Puppet agent: the standalone apply runs with an isolated - `--confdir`/`--vardir`, so it never collides with an existing agent's configuration or - state on the same host. -- Restart the runner gracefully: where the module owns the service, a restart drains running - jobs (SIGQUIT) instead of aborting them, tunable via a kill-signal and a stop-timeout, so a - legitimate restart never kills in-flight CI jobs. +- Opt-in toggles decide what the module owns on each host: the runner user and the rootless prerequisites it needs, the Docker and GitLab Runner apt repositories (so stock Ubuntu just works), the package set, and the runner service itself. +- Any toggle left off keeps the module hands-off that concern — safe to run alongside another configuration-management system that already owns the user, the daemon, or the repositories. +- Coexist with a central Puppet agent: the standalone apply runs with an isolated `--confdir`/`--vardir`, so it never collides with an existing agent's configuration or state on the same host. +- Restart the runner gracefully: where the module owns the service, a restart drains running jobs (SIGQUIT) instead of aborting them, tunable via a kill-signal and a stop-timeout, so a legitimate restart never kills in-flight CI jobs. #### Standalone self-update -- A single toggle turns a host into a self-converging runner: the module installs a - timer that pulls the control repository, verifies it, and re-applies on a schedule, so drift - corrects itself while every change stays review-gated through git. +- A single toggle turns a host into a self-converging runner: the module installs a timer that pulls the control repository, verifies it, and re-applies on a schedule, so drift corrects itself while every change stays review-gated through git. - Only signed commits on the protected branch are ever applied. -- A built-in health check continuously confirms the runner is healthy and the host has not - fallen behind on a stale checkout, surfacing problems through ordinary host monitoring. It also - verifies the apply timer is still enabled, so a halted self-update is caught at once. -- Route failures to your own alerting: an optional hook fires a systemd unit of your choice - when an apply or healthcheck run fails. +- A built-in health check continuously confirms the runner is healthy and the host has not fallen behind on a stale checkout, surfacing problems through ordinary host monitoring. It also verifies the apply timer is still enabled, so a halted self-update is caught at once. +- Route failures to your own alerting: an optional hook fires a systemd unit of your choice when an apply or healthcheck run fails. ### Security -- Rootless by design: the runner and its Docker daemon run as an unprivileged user, - not root; where the module manages the runner service, it runs privilege-dropped by default. -- With the rootless bring-up enabled, the module stops and masks the rootful system Docker - daemon and the idle root containerd service that installing `docker-ce`/`containerd.io` - otherwise leaves running as root, so the only container daemon on the host is the - unprivileged one. -- Runner tokens are handled as sensitive values end to end, so they stay out of compiled - catalogs, Puppet reports, and configuration diffs. -- Config inputs are escaped and type-checked where they are rendered, so a stray quote, - newline or malformed value in host data is escaped or rejected up front instead of - producing a broken or injected runner configuration. +- Rootless by design: the runner and its Docker daemon run as an unprivileged user, not root; where the module manages the runner service, it runs privilege-dropped by default. +- With the rootless bring-up enabled, the module stops and masks the rootful system Docker daemon and the idle root containerd service that installing `docker-ce`/`containerd.io` otherwise leaves running as root, so the only container daemon on the host is the unprivileged one. +- Runner tokens are handled as sensitive values end to end, so they stay out of compiled catalogs, Puppet reports, and configuration diffs. +- Config inputs are escaped and type-checked where they are rendered, so a stray quote, newline or malformed value in host data is escaped or rejected up front instead of producing a broken or injected runner configuration. [Unreleased]: https://github.com/eth-library/puppet-rootless_gitlab_runner/compare/v1.0.0...main [1.0.0]: https://github.com/eth-library/puppet-rootless_gitlab_runner/releases/tag/v1.0.0 From 9b9e509119f835e4fef7b22ecc1f43e750c48a2f Mon Sep 17 00:00:00 2001 From: jcardozo-eth <131674798+jcardozo-eth@users.noreply.github.com> Date: Thu, 9 Jul 2026 16:00:31 +0200 Subject: [PATCH 2/6] docs(changelog): trim over-explanation from 1.0.0 entries --- CHANGELOG.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5c10b4..ef7c8ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,38 +14,38 @@ The initial release: a rootless GitLab Runner host — runner config, the rootle ### Added #### Runner configuration -- Manage the entire GitLab Runner `config.toml` file from Hiera data — global settings and any number of runners on a single host, all from one node file. The module is never edited to onboard a host or team; host data drives it. +- Manage the entire GitLab Runner `config.toml` from Hiera data — global settings and any number of runners on a single host, all from one node file. - Declare values shared by every runner once (`url`, `image`, `executor`, …) and override per runner where needed. -- Support the Docker executor options runners actually use — images, volumes, environment, per-runner caching, and image/pull-policy allowlists — so the module stays out of the way of runner tuning. +- Support the Docker executor options runners actually use — images, volumes, environment, per-runner caching, and image/pull-policy allowlists. - Changes converge continuously: once a data change is applied, the runner adopts the new configuration on its own within seconds — no service restarts to arrange. -- Removing a runner is a data change too: drop its entry from Hiera and the next apply renders it out of the config, so the host stops offering it (delete the record on the GitLab side separately). +- Remove a runner as a data change: drop its entry from Hiera and the next apply renders it out (delete the record on the GitLab side separately). #### Rootless Docker -- Make the rootless-Docker `no-detach-netns` fix permanent, so routine package upgrades on Ubuntu 22.04 stop silently breaking rootless container networking. -- A toggle lets the module build the runner user's rootless Docker daemon from scratch — so a fresh host becomes a working runner from the module alone — or, left off, treats an existing daemon as a prerequisite. When it builds the daemon, a preflight checks the prerequisites first and stops with a clear message if any is missing. +- Make the rootless-Docker `no-detach-netns` fix permanent, so package upgrades on Ubuntu 22.04 stop silently breaking rootless container networking. +- Optionally build the runner user's rootless Docker daemon from scratch (with a preflight check on prerequisites), or, left off, treat an existing daemon as a prerequisite. #### Secrets - Keep runner tokens out of git: they live in an off-repository store on the host and are referenced by name, so neither the control repository nor the rendered configuration ever contains a secret. - Deploy pre-created GitLab runner tokens — the module never talks to the GitLab API, so an apply never depends on GitLab being reachable, and a host only ever holds its own runner token. -- Fail loudly on an unrecognized runner setting, and — when a secret store is present — on any runner whose token can't be resolved, so a typo (even in a security allowlist) stops the apply instead of silently bringing up a misconfigured runner. Without a store (dry-runs, CI validation), tokens render blank by design, so the configuration still compiles anywhere. +- Fail loudly on an unrecognized runner setting, or a token that can't be resolved when a secret store is present. Without a store, tokens render blank so the configuration still compiles. #### Flexible host ownership -- Opt-in toggles decide what the module owns on each host: the runner user and the rootless prerequisites it needs, the Docker and GitLab Runner apt repositories (so stock Ubuntu just works), the package set, and the runner service itself. -- Any toggle left off keeps the module hands-off that concern — safe to run alongside another configuration-management system that already owns the user, the daemon, or the repositories. -- Coexist with a central Puppet agent: the standalone apply runs with an isolated `--confdir`/`--vardir`, so it never collides with an existing agent's configuration or state on the same host. -- Restart the runner gracefully: where the module owns the service, a restart drains running jobs (SIGQUIT) instead of aborting them, tunable via a kill-signal and a stop-timeout, so a legitimate restart never kills in-flight CI jobs. +- Opt-in toggles decide what the module owns per host: the runner user and its rootless prerequisites, the Docker and GitLab Runner apt repositories, the package set, and the runner service. +- Any toggle left off keeps the module hands-off that concern, so it is safe to run alongside another configuration-management system. +- Coexist with a central Puppet agent: the standalone apply runs with an isolated `--confdir`/`--vardir`, so it never collides with an existing agent. +- Restart the runner gracefully: a restart drains running jobs (SIGQUIT) instead of aborting them, tunable via a kill-signal and stop-timeout. #### Standalone self-update -- A single toggle turns a host into a self-converging runner: the module installs a timer that pulls the control repository, verifies it, and re-applies on a schedule, so drift corrects itself while every change stays review-gated through git. +- A single toggle turns a host into a self-converging runner: a timer pulls the control repository, verifies it, and re-applies on a schedule, so drift corrects itself while every change stays review-gated through git. - Only signed commits on the protected branch are ever applied. -- A built-in health check continuously confirms the runner is healthy and the host has not fallen behind on a stale checkout, surfacing problems through ordinary host monitoring. It also verifies the apply timer is still enabled, so a halted self-update is caught at once. -- Route failures to your own alerting: an optional hook fires a systemd unit of your choice when an apply or healthcheck run fails. +- A built-in health check confirms the runner is healthy, the checkout is not stale, and the apply timer is still enabled, surfacing problems through ordinary host monitoring. +- Route failures to your own alerting: an optional hook fires a systemd unit when an apply or healthcheck run fails. ### Security -- Rootless by design: the runner and its Docker daemon run as an unprivileged user, not root; where the module manages the runner service, it runs privilege-dropped by default. -- With the rootless bring-up enabled, the module stops and masks the rootful system Docker daemon and the idle root containerd service that installing `docker-ce`/`containerd.io` otherwise leaves running as root, so the only container daemon on the host is the unprivileged one. +- Rootless by design: the runner and its Docker daemon run as an unprivileged user, and the runner service runs privilege-dropped by default. +- With rootless bring-up enabled, the module stops and masks the rootful system Docker daemon and the idle root containerd service, so the only container daemon on the host is the unprivileged one. - Runner tokens are handled as sensitive values end to end, so they stay out of compiled catalogs, Puppet reports, and configuration diffs. -- Config inputs are escaped and type-checked where they are rendered, so a stray quote, newline or malformed value in host data is escaped or rejected up front instead of producing a broken or injected runner configuration. +- Config inputs are escaped and type-checked where they are rendered, so a malformed value in host data is rejected up front instead of producing a broken or injected configuration. [Unreleased]: https://github.com/eth-library/puppet-rootless_gitlab_runner/compare/v1.0.0...main [1.0.0]: https://github.com/eth-library/puppet-rootless_gitlab_runner/releases/tag/v1.0.0 From d914e2151c22e395ea8b8cacf76e48b7315805b0 Mon Sep 17 00:00:00 2001 From: jcardozo-eth <131674798+jcardozo-eth@users.noreply.github.com> Date: Thu, 9 Jul 2026 16:00:46 +0200 Subject: [PATCH 3/6] docs(changelog): describe config reload accurately --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef7c8ed..8f02cab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ The initial release: a rootless GitLab Runner host — runner config, the rootle - Manage the entire GitLab Runner `config.toml` from Hiera data — global settings and any number of runners on a single host, all from one node file. - Declare values shared by every runner once (`url`, `image`, `executor`, …) and override per runner where needed. - Support the Docker executor options runners actually use — images, volumes, environment, per-runner caching, and image/pull-policy allowlists. -- Changes converge continuously: once a data change is applied, the runner adopts the new configuration on its own within seconds — no service restarts to arrange. +- A config change needs no service restart — GitLab Runner re-reads `config.toml` within seconds on its own. - Remove a runner as a data change: drop its entry from Hiera and the next apply renders it out (delete the record on the GitLab side separately). #### Rootless Docker From fef91938b59fe5a8dc6870ebb666a4130290d061 Mon Sep 17 00:00:00 2001 From: jcardozo-eth <131674798+jcardozo-eth@users.noreply.github.com> Date: Thu, 9 Jul 2026 16:00:55 +0200 Subject: [PATCH 4/6] docs(changelog): frame the token entry mechanism --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f02cab..2acc2a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,8 +25,8 @@ The initial release: a rootless GitLab Runner host — runner config, the rootle - Optionally build the runner user's rootless Docker daemon from scratch (with a preflight check on prerequisites), or, left off, treat an existing daemon as a prerequisite. #### Secrets -- Keep runner tokens out of git: they live in an off-repository store on the host and are referenced by name, so neither the control repository nor the rendered configuration ever contains a secret. -- Deploy pre-created GitLab runner tokens — the module never talks to the GitLab API, so an apply never depends on GitLab being reachable, and a host only ever holds its own runner token. +- Fetch runner tokens by name from an off-repository store on the host, so neither the control repository nor the rendered configuration contains a secret. +- The module consumes pre-created runner tokens and never calls the GitLab API, so an apply never depends on GitLab being reachable. - Fail loudly on an unrecognized runner setting, or a token that can't be resolved when a secret store is present. Without a store, tokens render blank so the configuration still compiles. #### Flexible host ownership From d7e3f6802607802bcf44fb2770f81d61fe96ab67 Mon Sep 17 00:00:00 2001 From: jcardozo-eth <131674798+jcardozo-eth@users.noreply.github.com> Date: Thu, 9 Jul 2026 16:01:04 +0200 Subject: [PATCH 5/6] docs(changelog): minor wording fixes --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2acc2a9..6c48da0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,11 +18,11 @@ The initial release: a rootless GitLab Runner host — runner config, the rootle - Declare values shared by every runner once (`url`, `image`, `executor`, …) and override per runner where needed. - Support the Docker executor options runners actually use — images, volumes, environment, per-runner caching, and image/pull-policy allowlists. - A config change needs no service restart — GitLab Runner re-reads `config.toml` within seconds on its own. -- Remove a runner as a data change: drop its entry from Hiera and the next apply renders it out (delete the record on the GitLab side separately). +- Remove a runner as a data change: drop its entry from Hiera and the next apply renders it out. #### Rootless Docker -- Make the rootless-Docker `no-detach-netns` fix permanent, so package upgrades on Ubuntu 22.04 stop silently breaking rootless container networking. -- Optionally build the runner user's rootless Docker daemon from scratch (with a preflight check on prerequisites), or, left off, treat an existing daemon as a prerequisite. +- Make the rootless-Docker `no-detach-netns` fix permanent, so package upgrades on Ubuntu 22.04 stop breaking rootless container networking. +- Optionally build the runner user's rootless Docker daemon from scratch, with a preflight check on prerequisites; or, left off, treat an existing daemon as a prerequisite. #### Secrets - Fetch runner tokens by name from an off-repository store on the host, so neither the control repository nor the rendered configuration contains a secret. From db5529dc940fd988a50786f5a1991363496f7b37 Mon Sep 17 00:00:00 2001 From: jcardozo-eth <131674798+jcardozo-eth@users.noreply.github.com> Date: Thu, 9 Jul 2026 16:08:41 +0200 Subject: [PATCH 6/6] docs(contributing): add a Changelog style-and-content section --- CONTRIBUTING.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8a80a8a..11236ae 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,6 +19,7 @@ merged and deployed. Consuming and operating the module on a host is covered by - [Change workflow](#change-workflow) - [Branching strategy](#branching-strategy) - [Commit rules](#commit-rules) +- [Changelog](#changelog) - [CI/CD](#cicd) - [Releases](#releases) - [References](#references) @@ -360,6 +361,41 @@ Repository-wide rules; they apply to every commit on every branch. [Releases](#releases): a renamed or removed parameter or Hiera key, a changed host-affecting default, or a dropped supported Puppet, Ruby, or operating-system version. +## Changelog + +`CHANGELOG.md` is consumer-facing: it follows Keep a Changelog [\[20\]](#ref-20), and its +per-version section is what the release workflow publishes verbatim as the GitHub Release +notes. Add an entry under `## [Unreleased]` in the same pull request as the change it +describes; at release time that section is rolled into the new version (see +[Releases](#releases)). + +**What earns an entry — consumer-visible changes only:** +- a new parameter, toggle, or Hiera key, or a change to an existing one; +- a change in a default, or in what the module manages; +- a fix in rendered configuration or applied host state; +- a new or dropped dependency, or a change in supported OS / Puppet range; +- a security-relevant change. + +Put it under the right Keep a Changelog category — Added, Changed, Deprecated, Removed, +Fixed, Security. Internal-only work earns no entry: refactors, tests, CI, and dev tooling. +Documentation changes usually don't either — the CHANGELOG tracks the module's behaviour and +interface, not its prose — but a substantial new piece of user-facing documentation (a guide, +a migration note) can warrant an **Added** entry. + +**Style — write for an operator reading the release notes:** +- State what changed and, where it helps an operator, a concrete benefit or why it matters. + One entry per user-visible change, a line or two at most. +- Lead with the change itself, not a meta-phrase like "Now supports…". +- Then stop. Cut vague or promotional justification, long rationale, how-to, and examples; + those belong in the README. +- Don't overclaim: describe what the module actually does, not an outcome it can't + guarantee. e.g. write "fetch tokens by name from an + off-repository store", not "keep tokens out of git". +- Leave out implementation detail, such as file modes, exit codes, internal environment + variables, or private class names. +- Write each entry as a single unwrapped line. It becomes the GitHub Release notes, where + wrapped lines break mid-sentence. + ## CI/CD The GitHub Actions [\[12\]](#ref-12) workflow `.github/workflows/ci.yml` runs the