carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package docsite
2
3import (
4 "strings"
5 "testing"
6)
7
8// knownFenceLangs is what a fence in this corpus may declare. Adding a
9// language here is a deliberate act: an undeclared or unknown fence is
10// invisible to every content gate that reads fences, so it is a way to
11// smuggle a wrong command past review.
12var knownFenceLangs = map[string]bool{
13 "sh": true, "bash": true, "console": true, "json": true,
14 "go": true, "yaml": true, "toml": true, "ini": true,
15 "text": true, "http": true,
16 // python, for the callback verifier on scan-callbacks.md. The page ships
17 // a second implementation on purpose: most people writing a webhook
18 // verifier against this platform are not writing Go, and the one mistake
19 // that page exists to prevent (hex secret, raw-byte key) is the one they
20 // make in whatever language they are in.
21 "python": true,
22}
23
24func TestFenceLanguagesAreDeclared(t *testing.T) {
25 site, err := Load(root)
26 if err != nil {
27 t.Fatalf("load: %v", err)
28 }
29 for _, p := range site.Pages() {
30 for _, f := range p.Fences {
31 if f.Lang == "" {
32 t.Errorf("%s.md:%d: fence declares no language", p.Slug, f.Line)
33 continue
34 }
35 if !knownFenceLangs[f.Lang] {
36 t.Errorf("%s.md:%d: unknown fence language %q — add it to knownFenceLangs if it is real",
37 p.Slug, f.Line, f.Lang)
38 }
39 }
40 }
41}
42
43// TestTestdataFencesDeclareLanguages runs the same rule against the
44// testdata corpus, so the gate above is proven to work on a corpus that
45// exists before docs/site does.
46func TestTestdataFencesDeclareLanguages(t *testing.T) {
47 site, err := Load(testCorpus)
48 if err != nil {
49 t.Fatalf("load: %v", err)
50 }
51 for _, p := range site.Pages() {
52 for _, f := range p.Fences {
53 if f.Lang == "" {
54 t.Errorf("%s: testdata corpus has an undeclared fence at line %d", p.Slug, f.Line)
55 }
56 }
57 }
58}
59
60// TestFencedCarlosCommandsAreReal checks the examples, not just the
61// prose. A renamed verb leaves every fence containing it copy-pasteable
62// and wrong, and nothing else in this package would notice.
63func TestFencedCarlosCommandsAreReal(t *testing.T) {
64 site, err := Load(root)
65 if err != nil {
66 t.Fatalf("load: %v", err)
67 }
68 cmds, err := TopLevelCommands(mainFile)
69 if err != nil {
70 t.Fatalf("scan: %v", err)
71 }
72 real := map[string]bool{}
73 for _, c := range cmds {
74 real[c] = true
75 }
76
77 for _, p := range site.Pages() {
78 for _, f := range p.Fences {
79 for _, verb := range fencedCarlosVerbs(f.Body) {
80 if !real[verb] {
81 t.Errorf("%s.md:%d: example runs `carlos %s`, which is not a command",
82 p.Slug, f.Line, verb)
83 }
84 }
85 }
86 }
87}
88
89// fencedCarlosVerbs returns the word after each "carlos" in a fence
90// body. It skips lines where "carlos" is not the command being run —
91// a path like /opt/carlos/carlos, or prose inside a comment.
92func fencedCarlosVerbs(body string) []string {
93 var out []string
94 for _, line := range strings.Split(body, "\n") {
95 line = strings.TrimSpace(line)
96 line = strings.TrimPrefix(line, "$ ")
97 // Treat # as starting a comment only when it is at index 0 or
98 // preceded by a space or tab. A # with a non-space before it
99 // (like a URL fragment) is not a comment.
100 if i := strings.Index(line, "#"); i >= 0 && (i == 0 || line[i-1] == ' ' || line[i-1] == '\t') {
101 line = strings.TrimSpace(line[:i])
102 }
103 fields := strings.Fields(line)
104 for i, f := range fields {
105 // Bare "carlos", or the binary called by an absolute path —
106 // runbooks on a box invoke /opt/carlos/carlos, and those
107 // examples go stale the same way.
108 if f != "carlos" && !strings.HasSuffix(f, "/carlos") {
109 continue
110 }
111 if i+1 >= len(fields) {
112 continue
113 }
114 next := fields[i+1]
115 if strings.HasPrefix(next, "-") {
116 continue
117 }
118 if next == "\\" {
119 continue
120 }
121 out = append(out, next)
122 }
123 }
124 return out
125}
126
127// TestFencedCarlosVerbsIgnoresNoise pins the parsing, because a
128// permissive extractor turns the gate above into one that finds
129// nothing.
130func TestFencedCarlosVerbsIgnoresNoise(t *testing.T) {
131 body := strings.Join([]string{
132 "carlos ship --app hello ./dist",
133 "$ carlos promote --app hello abc123 edge",
134 "/opt/carlos/carlos adopt",
135 "# run carlos deploy afterwards",
136 "carlos -h",
137 "echo carlos",
138 }, "\n")
139 got := fencedCarlosVerbs(body)
140 want := []string{"ship", "promote", "adopt"}
141 if len(got) != len(want) {
142 t.Fatalf("got %v, want %v", got, want)
143 }
144 for i := range want {
145 if got[i] != want[i] {
146 t.Fatalf("got %v, want %v", got, want)
147 }
148 }
149}
150
151// TestFencedCarlosVerbsCompoundLines verifies the extractor finds
152// multiple carlos invocations on a single line (Finding 1 fix).
153func TestFencedCarlosVerbsCompoundLines(t *testing.T) {
154 body := "carlos ship --app hello ./dist && carlos promote --app hello abc123 edge"
155 got := fencedCarlosVerbs(body)
156 want := []string{"ship", "promote"}
157 if len(got) != len(want) {
158 t.Fatalf("got %v, want %v", got, want)
159 }
160 for i := range want {
161 if got[i] != want[i] {
162 t.Fatalf("got %v, want %v", got, want)
163 }
164 }
165}
166
167// TestFencedCarlosVerbsURLFragment verifies the extractor does not
168// mistake URL fragments for comments (Finding 2 fix).
169func TestFencedCarlosVerbsURLFragment(t *testing.T) {
170 body := "curl -s https://carlosframework.com/docs/#cli && carlos ship --app website ./dist"
171 got := fencedCarlosVerbs(body)
172 want := []string{"ship"}
173 if len(got) != len(want) {
174 t.Fatalf("got %v, want %v", got, want)
175 }
176 for i := range want {
177 if got[i] != want[i] {
178 t.Fatalf("got %v, want %v", got, want)
179 }
180 }
181}
182
183// TestFencedCarlosVerbsBackslashContinuation verifies the extractor
184// does not extract backslash as a verb in line-continued invocations
185// (Finding 3 fix).
186func TestFencedCarlosVerbsBackslashContinuation(t *testing.T) {
187 body := "carlos \\"
188 got := fencedCarlosVerbs(body)
189 want := []string{}
190 if len(got) != len(want) {
191 t.Fatalf("got %v, want %v", got, want)
192 }
193}
194