Repository navigation
Commit a00522e
committed
ci: move the scan's exit-code gate into a tested script
The gate decides whether a scan that could not run is allowed to publish a
clean-looking result, and it was a shell body embedded in YAML — so the
only way to assert its behaviour was to pin the body's text and re-execute
it from the workflow's own shape test, under a stubbed docker.
As a script it can be tested directly: scan.test.sh feeds it every exit
code, checks that the ones meaning "did not scan" fail the job, checks the
argv the scanner receives and the lockfile it is handed at the moment of
the call, and checks that the results are not rewritten after it, on both
codes that pass.
Being a script is also what makes the container's reach assertable. It is
given the lockfile read-only and an output directory of its own, under the
runner's user rather than root, because the checkout's post step runs git
in that workspace with the token in its environment, so an image able to
write there is inside the reach of a step this file does not control. The
argv is pinned, so widening the mount again is red, and the script lint's
container runs as the same user, over the whole checkout read-only rather
than the one file.
What comes back out is checked too. The image decides what is left in its
output directory, so the results are copied only when they are a file the
scanner wrote rather than a link it aimed at one of the runner's.
A body that leaves YAML also leaves actionlint's reach, so the runner
lints the scripts with shellcheck, and the shape test requires each script
it names to be linted and to have a sibling test that a step runs. The
runner's bodies are an allowlist for the same reason its steps are: a step
running anything else runs before them and can rewrite what they assert.
The shape test reads scalars the way GitHub does rather than the way
PyYAML would: a timeout written 0400 is 400 to GitHub and 256 to PyYAML,
while hex and 0o octal are refused by the pinned actionlint in the same
job, as are cron field ranges like */0.
The stub records what the scanner receives at the moment it is called, so
a body that swaps the lockfile around the call and puts it back is not
invisible to a check made afterwards, and it writes more than the results
into its output directory, so what crosses back into the workspace is
asserted to be only them; it also leaves a link there, and nothing at all,
because both are what an image can hand back in place of a scan. Every
call is recorded rather than the last, and exactly one is expected, since
a container started before the pinned one reaches the workspace while the
argv still reads as pinned. The output directory has to be a different
path on each run, because a fixed one can be waited at. After each exit
code the test also looks for a process still holding that directory,
because work backgrounded and not waited for reaches the results after
the gate has passed on them; four decoys prove the four ways it looks.
That is aimed at a later edit leaving something running, not at an author,
who has easier ways and whom no test here constrains. The image the test
names is deliberately not the one the workflow ships, so a body that
hardcodes a digest rather than reading the one it is given is red, and the
link left at the results path is tested live as well as dangling, because
cp refuses the second and writes through the first.
shellcheck runs with --norc for the same reason actionlint runs with
-config-file /dev/null: a config file committed beside them would decide
what the lint reports.
The scripts and their tests are a pinned list, so a script named there is
linted, run, and has a test of its own. It is a guard against drift rather
than against whoever writes the diff, who can edit the list in the same
commit. shellcheck is pinned by the digest its own tag resolves to, so the
version named in the comment is one a reader can verify.
Signed-off-by: Nikita Kalyazin <nikita.kalyazin@e2b.dev>1 parent ad45e84 commit a00522e
5 files changed
Lines changed: 373 additions & 141 deletions
File tree
- .github
- scripts
- workflows
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 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 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
0 commit comments