Compare commits
1 Commits
ce103a7353
...
df5bfbbd3d
| Author | SHA1 | Date | |
|---|---|---|---|
| df5bfbbd3d |
@@ -43,14 +43,12 @@ The final acceptance criterion would then have passed while proving nothing, bec
|
|||||||
|
|
||||||
Two consequences follow, neither sanctioned by the spec.
|
Two consequences follow, neither sanctioned by the spec.
|
||||||
`passwd` no longer works, so rotating the password means re-running `mkpasswd`, re-encrypting the shared file, and rebuilding.
|
`passwd` no longer works, so rotating the password means re-running `mkpasswd`, re-encrypting the shared file, and rebuilding.
|
||||||
Root has no declared password and is therefore locked (`!`), which blocks direct root login and the systemd emergency shell's `sulogin` prompt.
|
Root has no declared password and is therefore locked (`!`), which blocks direct root login and the systemd emergency shell's `sulogin` prompt; `sudo` from the wheel group is unaffected, and generation rollback or `init=/bin/sh` remains available for recovery.
|
||||||
`sudo` from the wheel group is unaffected, and generation rollback or `init=/bin/sh` remains available for recovery.
|
|
||||||
Leaving root locked was chosen over declaring a root password, on the grounds that the recovery paths that survive a locked root do not depend on `/etc/shadow` at all.
|
Leaving root locked was chosen over declaring a root password, on the grounds that the recovery paths that survive a locked root do not depend on `/etc/shadow` at all.
|
||||||
This is worth folding back into the parent spec before the servers exist, where a locked root and no SSH key would be a harder corner.
|
This is worth folding back into the parent spec before the servers exist, where a locked root and no SSH key would be a harder corner.
|
||||||
|
|
||||||
**The negative half of the build criterion was exercised, not assumed.**
|
**The negative half of the build criterion was exercised, not assumed.**
|
||||||
A mistyped secret name fails with `the key 'alexion-passwrd' cannot be found`.
|
A mistyped secret name fails with `the key 'alexion-passwrd' cannot be found`; a missing secrets file fails with `Path 'secrets/absent.yaml' does not exist in Git repository`.
|
||||||
A missing secrets file fails with `Path 'secrets/absent.yaml' does not exist in Git repository`.
|
|
||||||
Both were tested by temporary edits that were reverted.
|
Both were tested by temporary edits that were reverted.
|
||||||
|
|
||||||
**Identity handling.**
|
**Identity handling.**
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
# Recipients for the encrypted files under secrets/.
|
# Recipients for the encrypted files under secrets/.
|
||||||
keys:
|
keys:
|
||||||
# A recipient of every file.
|
# A recipient of every file:
|
||||||
# One readable only by machines becomes unrecoverable once they are wiped.
|
# one readable only by machines is unrecoverable once they are wiped,
|
||||||
# Adding a recipient requires decrypting first.
|
# and adding a recipient requires decrypting first.
|
||||||
# No private half here, only in the operator's password manager.
|
# No private half here; it is held only in the operator's password manager.
|
||||||
- &admin age1m0pk94ysjlw3lmf6pyuv5l5pepvdjss8w0vxjv90dq6ndp02tdgsdwdvue
|
- &admin age1m0pk94ysjlw3lmf6pyuv5l5pepvdjss8w0vxjv90dq6ndp02tdgsdwdvue
|
||||||
# Generated on the machine it names.
|
# Generated on the machine it names.
|
||||||
- &neogaia age14a04vphzjq74epfrz9a09wjw8lzchtru84awzuq2n45d8f42ychqjs89qe
|
- &neogaia age14a04vphzjq74epfrz9a09wjw8lzchtru84awzuq2n45d8f42ychqjs89qe
|
||||||
|
|||||||
10
CLAUDE.md
10
CLAUDE.md
@@ -15,12 +15,10 @@ The domain model (Host, Module, Skeleton, Auto-loader, Enable convention, overla
|
|||||||
A file-top header is one concise purpose line, added only where the filename or path does not already say it — never a feature inventory of the code below.
|
A file-top header is one concise purpose line, added only where the filename or path does not already say it — never a feature inventory of the code below.
|
||||||
For a placeholder, say so plainly plus any actionable present-tense directive ("Placeholder: regenerate with nixos-generate-config on the target machine"), never "placeholder for <missing feature>".
|
For a placeholder, say so plainly plus any actionable present-tense directive ("Placeholder: regenerate with nixos-generate-config on the target machine"), never "placeholder for <missing feature>".
|
||||||
Option `description`/`mkEnableOption` strings are user-facing documentation rather than comments, so they may describe behaviour more fully — but the self-contained rule and the bans on glossary terms and agent-state references still apply.
|
Option `description`/`mkEnableOption` strings are user-facing documentation rather than comments, so they may describe behaviour more fully — but the self-contained rule and the bans on glossary terms and agent-state references still apply.
|
||||||
- Start each sentence of a comment on its own line, as with Markdown prose.
|
- Break comment lines early, at sentence and clause boundaries, rather than greedy-wrapping at the right margin.
|
||||||
A sentence needing more than one line is first a prompt to ask whether it should be two sentences.
|
Start each sentence on its own line, and when one sentence needs several lines, break it at a comma or semicolon rather than mid-phrase.
|
||||||
Only when it genuinely cannot be split does it wrap, and then it wraps normally at the right margin.
|
A line that ends mid-noun-phrase ("keeps the SSH host keys out / of the decryption path") is the smell.
|
||||||
Never break a line early at a comma or clause boundary to make it read as a unit.
|
This is the Markdown one-sentence-per-line rule applied to code comments; lines may end well short of the margin.
|
||||||
Never use a semicolon, in a comment or in authored prose.
|
|
||||||
Recast as two sentences instead.
|
|
||||||
Only reformat comments you are actually writing or changing.
|
Only reformat comments you are actually writing or changing.
|
||||||
- Comments posted to Gitea (pull requests, issues, reviews) go out under the operator's account, so sign every one to make clear the author is the agent, not the operator.
|
- Comments posted to Gitea (pull requests, issues, reviews) go out under the operator's account, so sign every one to make clear the author is the agent, not the operator.
|
||||||
End the comment with a `— Claude` sign-off.
|
End the comment with a `— Claude` sign-off.
|
||||||
|
|||||||
@@ -69,23 +69,23 @@ in
|
|||||||
console.useXkbConfig = true;
|
console.useXkbConfig = true;
|
||||||
|
|
||||||
# Decryption machinery every host depends on.
|
# Decryption machinery every host depends on.
|
||||||
# The identity sits on the encrypted root, which is mounted early enough to
|
# The identity sits on the encrypted root,
|
||||||
# satisfy the secret below.
|
# which is mounted early enough to satisfy the secret below.
|
||||||
# Clearing both `sshKeyPaths` defaults keeps the SSH host keys out of the
|
# Clearing both `sshKeyPaths` defaults keeps the SSH host keys
|
||||||
# decryption path.
|
# out of the decryption path.
|
||||||
sops.defaultSopsFile = ../secrets/shared.yaml;
|
sops.defaultSopsFile = ../secrets/shared.yaml;
|
||||||
sops.age.keyFile = "/var/lib/sops-nix/key.txt";
|
sops.age.keyFile = "/var/lib/sops-nix/key.txt";
|
||||||
sops.age.sshKeyPaths = [ ];
|
sops.age.sshKeyPaths = [ ];
|
||||||
sops.gnupg.sshKeyPaths = [ ];
|
sops.gnupg.sshKeyPaths = [ ];
|
||||||
|
|
||||||
# A password set by hand on a running machine otherwise takes precedence.
|
# A password set by hand on a running machine otherwise takes precedence,
|
||||||
# That leaves the declared `hashedPasswordFile` below silently inert.
|
# leaving the declared `hashedPasswordFile` below silently inert.
|
||||||
# Root has no declared password and is therefore locked.
|
# Root has no declared password and is therefore locked;
|
||||||
# `sudo` from the wheel group is the way in.
|
# `sudo` from the wheel group is the way in.
|
||||||
users.mutableUsers = false;
|
users.mutableUsers = false;
|
||||||
|
|
||||||
# Decrypted in an earlier activation stage than ordinary secrets.
|
# Decrypted in an earlier activation stage,
|
||||||
# That is early enough to precede the account that reads it.
|
# so it exists before the account that reads it.
|
||||||
sops.secrets.${passwordSecret}.neededForUsers = true;
|
sops.secrets.${passwordSecret}.neededForUsers = true;
|
||||||
|
|
||||||
# Primary user, in the wheel group.
|
# Primary user, in the wheel group.
|
||||||
|
|||||||
Reference in New Issue
Block a user