1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# Probation sample configuration (SPEC §4).
#
# Configuration changes require a restart; blocklist changes do not.
= "127.0.0.1:8080"
= "https://packages.example.org"
= "/var/lib/probation"
# The snapshot your blocklist producer writes and replaces atomically. It is not
# the `blocklist.sample.json` in this repository: that sample carries a deliberately
# distant `expires_at` so it always validates, while a producer's real snapshot
# carries a short window. Without a valid snapshot the service starts, answers
# /health/live but not /health/ready, and refuses every package request.
= "/etc/probation/blocklist.json"
= 86400
= 300
# How old a cached project snapshot may become since its last FULL fetch, whatever
# upstream keeps answering `304` to (SPEC §10). Each project's own ceiling is this
# value less a deterministic offset of up to a tenth, so projects fetched together do
# not all expire at once; the offset only ever shortens, so this stays a true
# maximum. An over-age snapshot is never served: if the full fetch fails the request
# is refused. Must not be below `metadata_ttl_seconds`. Set 0 to disable the ceiling
# — which restores exactly the unbounded staleness it exists to close.
= 86400
= 5
= 107374182400 # 100 GiB, including temporary downloads
= 268435456 # 256 MiB cache budget, not total process RSS
= 5368709120 # 5 GiB
= 67108864 # 64 MiB after decompression
= 134217728 # 128 MiB
= 32
= 8
= 1024
= 20000
# Decision log delivery (§8 of docs/operations.md). Both keys are absent by default:
# with no `log_file_path` this process opens no file and starts no delivery task, and
# the stdout decision line is unchanged.
#
# Every decision is appended to this file as one JSON object per line, in addition to
# stdout. Exactly one process may write it, and it must not be handed to an external
# `logrotate` — this process renames the file itself.
# log_file_path = "/var/log/probation/decisions.ndjson"
# The live file is rolled to `<log_file_path>.1` when it reaches this size, replacing
# any previous `.1`. One generation is kept, so the pair costs at most twice this.
# Has no effect without `log_file_path`, and is refused rather than ignored.
# log_file_max_bytes = 104857600 # 100 MiB live, 200 MiB with the rollover
# How much memory this sink's queue may hold while the file falls behind — a memory
# budget, like `memory_cache_max_bytes`, and additive to it. Records are dropped and
# counted once the queue is full, so this trades memory for headroom against a slow
# disk. Absent means 64 MiB. Has no effect without `log_file_path`, and is refused
# rather than ignored.
# log_queue_max_bytes = 67108864 # 64 MiB
# The collector decisions are also POSTed to, batched as newline-delimited JSON at 256
# records or two seconds, whichever comes first. Absent by default: with no `siem_url`
# no HTTP client is built and no delivery task is started. Must use `https` unless the
# host is a loopback address or `localhost`.
# siem_url = "https://siem.example.org/services/collector/raw"
# The header the credential is sent under. The credential itself is never written here:
# it is read from the environment variable `PROBATION_SIEM_AUTH` at startup, and delivery
# is unauthenticated when that variable is unset. Has no effect without `siem_url`, and
# is refused rather than ignored.
# siem_auth_header = "Authorization"
# The same budget for this sink's queue, and the one that decides how long a collector
# outage costs nothing: records accumulate here while the collector is away and are
# dropped and counted once it is full. Absent means 64 MiB. Two sinks are two queues,
# so a deployment with both configured pays both. Has no effect without `siem_url`,
# and is refused rather than ignored.
# siem_queue_max_bytes = 67108864 # 64 MiB
# Whether every delivered record also carries the peer IP of the connection that asked,
# as a `consumer` field. Off by default, and with it off no record carries the field at
# all. Privacy note: this records who is installing packages. What is recorded is the
# peer address of the accepted TCP connection — never a port, and never anything the
# caller supplies. Behind a forwarding hop, NAT or load balancer it identifies that
# hop, not the machine that ran the install — see §8 of docs/operations.md. Turning it
# off later erases nothing already written — in the log file, its `.1`, the collector,
# or the host's console log, since the address is on the stdout decision line too.
# The log file is created 0600; a pre-existing file keeps its mode and a group- or
# world-accessible one is warned about once. With this on, a `log_file_path` that
# cannot be opened stops startup.
# Refused at startup without `log_file_path` or `siem_url`, so the addresses it records
# reach a durable destination the operator chose.
# log_consumer_identification = false
# OSV vulnerability intelligence: every candidate a producer's own blocklist would
# otherwise allow is also checked against OSV before it is served. A candidate is
# never blocked while an OSV lookup is unresolved: an absent, slow or unreachable OSV
# endpoint costs staleness, never availability.
#
# How long an OSV lookup's answer is trusted before it is asked again. Optional,
# and 300 (5 minutes) if left out.
= 300
# How long one OSV batch flush's outbound call may take before it fails open.
# Optional, and 500 if left out.
= 500
# Whether OSV enforcement denies (`enforce`), only checks and logs a match without
# denying (`diagnostic`), or is skipped entirely (`off`). Optional, and `enforce` if
# left out — today's behaviour. Changing it requires a restart, like every other key.
= "enforce"