Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

Code

392 commit(s) on main

Merge change request 01M70WES5ZZDJ6RP226WB11BBZ: Let people rename and remove their own passkeys keenan · 23m ago 4b8c9e1d
history blame raw 2.8 KiB
1package server_test
2
3// The deployment baseline, checked the way an operator would: look at the modes
4// of everything a fresh instance creates and refuse to be surprised by one.
5
6import (
7 "io"
8 "log/slog"
9 "os"
10 "path/filepath"
11 "testing"
12
13 "rodent.software/vole/server"
14)
15
16// TestFreshInstanceCreatesNoReadableSecrets is the acceptance criterion for a
17// new install: the roster, the host key and the audit log are for the service
18// account, not for everyone with a shell.
19func TestFreshInstanceCreatesNoReadableSecrets(t *testing.T) {
20 t.Parallel()
21 f := newFixture(t)
22
23 // A privileged operation, so the audit log exists and is written by the code
24 // that will write it in production.
25 f.addWriter(t)
26
27 paths := []string{
28 f.cfg.DataDir,
29 f.cfg.UsersDB(),
30 f.cfg.IndexDB(),
31 f.cfg.RunsDB(),
32 f.cfg.SSHHostKey(),
33 f.cfg.AuditLog(),
34 }
35 for _, path := range paths {
36 st, err := os.Stat(path)
37 if err != nil {
38 t.Fatalf("%s: %v", path, err)
39 }
40 mode := st.Mode().Perm()
41 if st.IsDir() {
42 if mode&0o007 != 0 {
43 t.Errorf("%s is %04o: world-accessible", path, mode)
44 }
45 continue
46 }
47 if mode&0o077 != 0 {
48 t.Errorf("%s is %04o: readable beyond the service account", path, mode)
49 }
50 }
51}
52
53// TestUpgradedInstanceHasItsSecretsTightened covers the instance that already
54// existed: the files are there, and they were created 0644.
55func TestUpgradedInstanceHasItsSecretsTightened(t *testing.T) {
56 t.Parallel()
57 f := newFixture(t)
58 f.addWriter(t)
59
60 for _, path := range []string{f.cfg.UsersDB(), f.cfg.SSHHostKey(), f.cfg.AuditLog()} {
61 if err := os.Chmod(path, 0o644); err != nil {
62 t.Fatal(err)
63 }
64 }
65
66 // Starting the instance is what tightens them, so build a second server over
67 // the same directory the way a restart does.
68 restarted, err := server.New(f.cfg, binPath, slog.New(slog.NewTextHandler(io.Discard, nil)))
69 if err != nil {
70 t.Fatalf("restart refused to start over an instance with loose modes: %v", err)
71 }
72 t.Cleanup(func() { restarted.Close() })
73
74 for _, path := range []string{f.cfg.UsersDB(), f.cfg.SSHHostKey(), f.cfg.AuditLog()} {
75 st, err := os.Stat(path)
76 if err != nil {
77 t.Fatal(err)
78 }
79 if mode := st.Mode().Perm(); mode&0o077 != 0 {
80 t.Errorf("%s is %04o after a restart", path, mode)
81 }
82 }
83}
84
85// TestBackupIsNotWorldReadable: `vole admin account backup` writes every account,
86// key and passkey to a path the operator chooses, so the copy needs the mode the
87// original has.
88func TestBackupIsNotWorldReadable(t *testing.T) {
89 t.Parallel()
90 f := newFixture(t)
91 f.addWriter(t)
92
93 dst := filepath.Join(t.TempDir(), "roster.db")
94 if err := f.srv.Identity.Backup(dst); err != nil {
95 t.Fatal(err)
96 }
97 st, err := os.Stat(dst)
98 if err != nil {
99 t.Fatal(err)
100 }
101 if mode := st.Mode().Perm(); mode&0o077 != 0 {
102 t.Fatalf("%s is %04o: the backup is readable beyond its owner", dst, mode)
103 }
104}
105