Case Study: Keeping Changes to a Vendor TOML Config Through an Upgrade
This case uses the examples/vendor-app-toml folder that ships in every download archive, so you can run each step yourself. The vendor app is a stand-in. The commands and output below come from a real run of the downloaded aftermarket 0.7.0.
The situation
A team runs a vendor’s app that reads config.toml. The vendor writes good comments in that file, and replaces it on every upgrade. The team needs seven changes: a longer timeout, more workers, JSON logs, no telemetry, their own database password, a bigger pool, and the weekly report moved to Sunday.
Editing the file by hand works until the next upgrade wipes it. Keeping a copy of the whole file means missing whatever the vendor changes next. So the changes live in an overlay, most of them guarded by the value they expect to find:
version: 1
base: 1.0/config.toml
changes:
- set: {path: server.timeout, value: 120, expect: 30}
- set: {path: server.workers, value: 8, expect: 4}
- set: {path: logging.format, value: json, expect: text}
- set: {path: telemetry.enabled, value: false, expect: true}
- set: {path: database.password, value: from-our-vault}
- set: {path: database.pool, value: 25, expect: 10}
- set: {path: jobs.1.schedule, value: "0 6 * * 0", expect: "0 6 * * 1"}
jobs.1 is the second [[jobs]] table in the vendor’s file.
Checking it first
$ aftermarket config check --overlay examples/vendor-app-toml/overlay.yaml
examples/vendor-app-toml/overlay.yaml: 7 change(s) to examples/vendor-app-toml/1.0/config.toml (toml)
1. line 9: set server.timeout to 120, guarded
2. line 12: set server.workers to 8, guarded
3. line 15: set logging.format to "json", guarded
4. line 18: set telemetry.enabled to false, guarded
5. line 21: set database.password to REDACTED
6. line 22: set database.pool to 25, guarded
7. line 25: set jobs.1.schedule to "0 6 * * 0", guarded
ok
The password never shows, in check or in diff:
$ aftermarket config diff --overlay examples/vendor-app-toml/overlay.yaml
~ server.timeout: 30 -> 120
~ server.workers: 4 -> 8
~ logging.format: "text" -> "json"
~ telemetry.enabled: true -> false
~ database.password: REDACTED -> REDACTED
~ database.pool: 10 -> 25
~ jobs.1.schedule: "0 6 * * 1" -> "0 6 * * 0"
Applying it
$ aftermarket config apply --overlay examples/vendor-app-toml/overlay.yaml --out config.toml
wrote config.toml: 7 change(s) applied, 0 already in place
Here’s everything that differs between the vendor’s file and the result:
$ diff examples/vendor-app-toml/1.0/config.toml config.toml
6,7c6,7
< timeout = 30 # seconds
< workers = 4
---
> timeout = 120 # seconds
> workers = 8
11c11
< format = "text" # text or json
---
> format = "json" # text or json
14c14
< enabled = true
---
> enabled = false
19,20c19,20
< password = "vendor-default"
< pool = 10
---
> password = "from-our-vault"
> pool = 25
28c28
< schedule = "0 6 * * 1"
---
> schedule = "0 6 * * 0"
Seven changed lines, comments still on them, and nothing else touched. The vendor’s header comment, the section order and the blank lines all come through as they were. Running apply again gives the same bytes, so a deploy step can run it every time.
The upgrade
Version 1.1 arrives. The vendor raised the default timeout to 60 and made JSON logging the default, so two of the team’s guards no longer hold:
$ aftermarket config apply --overlay examples/vendor-app-toml/overlay.yaml \
--base examples/vendor-app-toml/1.1/config.toml --out config.toml
examples/vendor-app-toml/overlay.yaml: 2 of 7 change(s) can't be applied to examples/vendor-app-toml/1.1/config.toml
line 9: set expects server.timeout to be 30, but the base has 60
line 15: set expects logging.format to be "text", but the base has "json"
nothing was written
Exit code 1, and the config.toml from the last good apply is still there, byte for byte. Nothing half-applied reaches the app.
What the team does next
Each stop is a question for a person. The timeout: the vendor’s 60 is still too short for their reports, so they keep 120 and update the guard to expect: 60. The log format: the vendor now does what they wanted, so that change comes out of the overlay. Two edits to the overlay, with base pointed at the new file, and apply goes through on 1.1:
wrote config.toml: 6 change(s) applied, 0 already in place
The vendor’s new comment on the timeout line, # seconds; raised in 1.1, stays in the output, and so does the http2 = true line 1.1 added.
The overlay’s own fixture runs in CI, so the next person to touch it finds out before a deploy does:
$ aftermarket config test --overlay examples/vendor-app-toml/overlay.yaml --fixture examples/vendor-app-toml/fixture.yaml
PASS the overlay applies to the 1.0 config
PASS an upgrade that changes the timeout default stops apply
2 case(s), 0 failed
The full format is in the AfterConfig reference.