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 ansible/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ control machine):

```bash
umask 077
sudo install -m 600 -o root -g root grafana-alloy.env /etc/decdn/grafana-alloy.env
sudo install -m 600 -o root -g root grafana-alloy.env /etc/grafana-alloy.env
```

with `roles/grafana_alloy/files/grafana-alloy.env.example` as the template (remote-write
Expand Down
14 changes: 14 additions & 0 deletions ansible/galaxy/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,20 @@ collection adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
a missing port, a path/query/fragment and userinfo are rejected at deploy time.
OTLP export is always compiled in; no `--features otlp` build is needed.

### Fixed

- Grafana Alloy credentials now default to root-controlled
`/etc/grafana-alloy.env`; preflight also rejects a non-root-owned or writable
parent directory and a root service identity. Teardown requires the managed
stamp on the unit's first line, and destructive paths reject both `.` and `..`
segments.
- `decdn config validate` no longer bash-sources `/etc/decdn/decdn.env`. It
loads the role-supported one-line EnvironmentFile assignment forms with a
non-expanding host-side parser, so `$VAR` / `$(...)` in an inventory-rendered
(`to_json`) RPC URL stay literal for both the gate and the daemon.
- Manual dir-mode's read-only ELF probe runs under `--check` instead of being
skipped and feeding empty output into the architecture assertion.

## [0.1.0] — unreleased

Initial packaging of the public deCDN node roles as a distributable collection.
Expand Down
8 changes: 7 additions & 1 deletion ansible/molecule/default/converge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@
# (install.yml) instead of letting it degrade to a bare liveness check. Must
# stay in sync with the version string printed by files/decdn-node-stub.
decdn_node_version: "0.0.0-molecule-stub"
decdn_rpc_url: "https://rpc.example.invalid/"
# Shell metacharacters + a single quote are deliberate: the role's host-side
# EnvironmentFile parser must preserve the value literally without executing
# the command substitution (the stub + verify.yml check both properties).
decdn_rpc_url: "https://rpc.example.invalid/?token=$HOME$(touch /tmp/decdn-rpc-expanded)&quote=o'brien"
# The ACCEPTED side of the decdn_extra_env gate (#39): with an inventory
# decdn_rpc_url the role authors the whole env file, so extra_env is rendered
# rather than rejected. Nothing else in any scenario sets it alongside a
Expand All @@ -26,6 +29,9 @@
# escape means the variable is silently absent at runtime.
decdn_extra_env:
DECDN_MOLECULE_EXTRA: 'a "quoted" \ value'
# Makes the stub compare the environment received by `config validate`
# against the exact literal above (not merely assert that no command ran).
DECDN_MOLECULE_ASSERT_RPC_LITERAL: "1"
decdn_chain_id: 421614
decdn_region: "US"
decdn_payment_pool_address: "0x1111111111111111111111111111111111111111"
Expand Down
20 changes: 19 additions & 1 deletion ansible/molecule/default/files/decdn-node-stub
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ can be exercised end-to-end without a published release or a live chain:
scenario uses this to prove the role's advisory probe warns
(not fails) on timeout while the unit stays `running`.
* `config validate ...`
-> parse the rendered node.toml as TOML and exit 0. A stub has no
-> parse the rendered node.toml as TOML and exit 0. In the default
scenario it also checks the exact literal DECDN_RPC_URL passed
by the role's non-expanding EnvironmentFile loader. A stub has no
schema, so this checks syntax only; `molecule/schema` is what
covers key-level drift against the real upstream field list.
* `key-gen ...` -> stand in for the CLI's wallet generator (exercised by the
Expand Down Expand Up @@ -128,6 +130,22 @@ def config_validate(args):
if not os.path.isfile(config):
print(f"stub config validate: no such config file: {config}", file=sys.stderr)
return 1
if os.environ.get("DECDN_MOLECULE_ASSERT_RPC_LITERAL") == "1":
expected_rpc = (
"https://rpc.example.invalid/?token=$HOME"
"$(touch /tmp/decdn-rpc-expanded)&quote=o'brien"
)
expected_extra = 'a "quoted" \\ value'
if (
os.environ.get("DECDN_RPC_URL") != expected_rpc
or os.environ.get("DECDN_MOLECULE_EXTRA") != expected_extra
):
print(
"stub config validate: an EnvironmentFile value was expanded or "
"decoded incorrectly",
file=sys.stderr,
)
return 1
try:
with open(config, "rb") as fh:
tomllib.load(fh)
Expand Down
18 changes: 16 additions & 2 deletions ansible/molecule/default/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,23 @@
decdn_extra_env value correctly. Got: {{ env_body }}
vars:
env_body: "{{ decdn_env_body.content | b64decode }}"
env_rpc_expected: 'DECDN_RPC_URL="https://rpc.example.invalid/"'
env_rpc_expected: >-
DECDN_RPC_URL="https://rpc.example.invalid/?token=$HOME$(touch /tmp/decdn-rpc-expanded)&quote=o'brien"
env_expected: 'DECDN_MOLECULE_EXTRA="a \"quoted\" \\ value"'

- name: Check whether sourcing the RPC URL executed its command substitution
ansible.builtin.stat:
path: /tmp/decdn-rpc-expanded
register: decdn_rpc_expansion_marker

- name: Assert config validate did not expand the RPC URL as a shell
ansible.builtin.assert:
that:
- not decdn_rpc_expansion_marker.stat.exists
fail_msg: >-
config validate expanded a literal command substitution embedded in
decdn_rpc_url; the env file must be loaded without bash source.

- name: Compute the env file's current sha256
ansible.builtin.stat:
path: "{{ decdn_etc }}/decdn.env"
Expand Down Expand Up @@ -352,7 +366,7 @@
- /etc/alloy
- /var/lib/alloy
- /etc/systemd/system/alloy.service
- /etc/decdn/grafana-alloy.env
- /etc/grafana-alloy.env

- name: Assert no Alloy artifacts exist while observability is disabled
ansible.builtin.assert:
Expand Down
2 changes: 1 addition & 1 deletion ansible/molecule/grafana-cloud/prepare.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
# non-empty). Written directly at 0600 because preflight refuses anything else.
- name: Stage the Grafana Cloud credential fixture on the host
ansible.builtin.copy:
dest: /etc/decdn/grafana-alloy.env
dest: /etc/grafana-alloy.env
owner: root
group: root
mode: "0600"
Expand Down
10 changes: 6 additions & 4 deletions ansible/molecule/grafana-cloud/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
register: ga_files
loop:
- {path: /etc/alloy/config.alloy, mode: "0644"}
- {path: /etc/decdn/grafana-alloy.env, mode: "0600"}
- {path: /etc/grafana-alloy.env, mode: "0600"}
- {path: /etc/systemd/system/alloy.service, mode: "0644"}

- name: Assert ownership/modes of the Alloy artifacts
Expand Down Expand Up @@ -101,7 +101,7 @@
# --- Secret hygiene -------------------------------------------------------------
- name: Read the credential fixture back
ansible.builtin.slurp:
src: /etc/decdn/grafana-alloy.env
src: /etc/grafana-alloy.env
register: ga_env_b64

- name: Assert the env file carries every required key verbatim
Expand Down Expand Up @@ -174,7 +174,7 @@
ansible.builtin.assert:
that:
- >-
'EnvironmentFile=/etc/decdn/grafana-alloy.env' in ga_unit
'EnvironmentFile=/etc/grafana-alloy.env' in ga_unit
# Alloy defines no --config.expand-env and no gRPC admin listener;
# either flag makes `alloy run` exit non-zero, i.e. a crash-loop.
# Checked against the ExecStart flag lines ONLY — the unit's comments
Expand Down Expand Up @@ -266,7 +266,7 @@
- /etc/alloy
- /var/lib/alloy

- name: Stage a foreign Alloy installation (no managed-by marker)
- name: Stage a foreign Alloy installation (marker mentioned after line one)
ansible.builtin.copy:
dest: "{{ item.path }}"
content: "{{ item.content }}"
Expand All @@ -276,6 +276,8 @@
content: |
[Unit]
Description=Somebody else's Alloy
# This role used to write:
# MANAGED BY the grafana_alloy role — do not edit by hand.
[Service]
ExecStart=/bin/true
- path: /etc/alloy/config.alloy
Expand Down
13 changes: 13 additions & 0 deletions ansible/molecule/slow-readiness/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,19 @@
- name: Gather service facts
ansible.builtin.service_facts:

- name: Read node.toml for the disabled-observability branch
ansible.builtin.slurp:
src: /etc/decdn/node.toml
register: node_toml_b64

- name: Assert disabled Grafana with no explicit endpoint omits OTLP entirely
ansible.builtin.assert:
that:
- "'otlp_endpoint' not in (node_toml_b64.content | b64decode)"
fail_msg: >-
node.toml rendered observability.otlp_endpoint even though both
decdn_grafana_cloud_enabled is false and decdn_otlp_endpoint is empty.

- name: Assert the deploy survived a metrics-probe timeout with the unit running
ansible.builtin.assert:
that:
Expand Down
Loading
Loading