Skip to content

Commit 93f3dab

Browse files
authored
runtime: improve workspace runtime
1 parent 9005cf2 commit 93f3dab

22 files changed

Lines changed: 923 additions & 123 deletions

File tree

.github/workflows/publish-nix-cache.yml

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,22 @@ jobs:
2727
- uses: actions/checkout@v6
2828
- uses: ./.github/actions/setup-nix
2929

30-
- name: Build dev shell
30+
- name: Build dev shell closures
3131
id: build-dev-shell
3232
run: |
33-
printf 'path=%s\n' "$(nix build --no-link --print-out-paths .#devShells.x86_64-linux.default)" >> "${GITHUB_OUTPUT}"
33+
{
34+
echo 'paths<<EOF'
35+
nix build --no-link --print-out-paths .#devShells.x86_64-linux.default
36+
nix build --no-link --print-out-paths .#devShells.x86_64-linux.full
37+
echo EOF
38+
} >> "${GITHUB_OUTPUT}"
3439
35-
- name: Sign dev shell closure
40+
- name: Sign dev shell closures
41+
env:
42+
DEV_SHELL_PATHS: ${{ steps.build-dev-shell.outputs.paths }}
3643
run: |
37-
nix store sign --recursive --key-file <(echo '${{ secrets.NIX_CACHE_PRIVATE_KEY }}') '${{ steps.build-dev-shell.outputs.path }}'
44+
mapfile -t paths <<< "${DEV_SHELL_PATHS}"
45+
nix store sign --recursive --key-file <(echo '${{ secrets.NIX_CACHE_PRIVATE_KEY }}') "${paths[@]}"
3846
3947
- name: Configure AWS credentials
4048
shell: 'nix shell nixpkgs#awscli2 --command bash --noprofile --norc -euo pipefail {0}'
@@ -46,20 +54,24 @@ jobs:
4654
aws configure set aws_secret_access_key "${AWS_SECRET_ACCESS_KEY}"
4755
aws configure set region auto
4856
49-
- name: Publish dev shell closure to R2 cache
57+
- name: Publish dev shell closures to R2 cache
5058
shell: 'nix shell nixpkgs#awscli2 --command bash --noprofile --norc -euo pipefail {0}'
5159
env:
60+
DEV_SHELL_PATHS: ${{ steps.build-dev-shell.outputs.paths }}
5261
R2_BUCKET_NAME: challenges-nix-cache
5362
R2_ENDPOINT: ${{ secrets.R2_ACCOUNT_ID }}.r2.cloudflarestorage.com
5463
run: |
55-
nix copy --to "s3://${R2_BUCKET_NAME}?endpoint=${R2_ENDPOINT}" '${{ steps.build-dev-shell.outputs.path }}'
64+
mapfile -t paths <<< "${DEV_SHELL_PATHS}"
65+
nix copy --to "s3://${R2_BUCKET_NAME}?endpoint=${R2_ENDPOINT}" "${paths[@]}"
5666
printf 'StoreDir: /nix/store\nPriority: 50\n' | aws s3 cp - "s3://${R2_BUCKET_NAME}/nix-cache-info" \
5767
--content-type text/x-nix-cache-info \
5868
--endpoint-url "https://${R2_ENDPOINT}" \
5969
>/dev/null
6070
6171
- name: Check cache availability from public domain
6272
env:
73+
DEV_SHELL_PATHS: ${{ steps.build-dev-shell.outputs.paths }}
6374
R2_PUBLIC_CACHE_DOMAIN: nix-cache.challenges.pwn.college
6475
run: |
65-
nix path-info --store "https://${R2_PUBLIC_CACHE_DOMAIN}" '${{ steps.build-dev-shell.outputs.path }}' >/dev/null
76+
mapfile -t paths <<< "${DEV_SHELL_PATHS}"
77+
nix path-info --store "https://${R2_PUBLIC_CACHE_DOMAIN}" "${paths[@]}" >/dev/null

flake.nix

Lines changed: 119 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,55 @@
2121
lib = nixpkgs.lib;
2222
systems = [ "x86_64-linux" ];
2323
forAllSystems = f: lib.genAttrs systems (system: f system);
24+
workspaceFor =
25+
pkgs:
26+
{
27+
packageProfile ? (
28+
let
29+
packageProfileEnv = builtins.getEnv "PWN_WORKSPACE_PACKAGES";
30+
in
31+
if packageProfileEnv == "" then "minimal" else packageProfileEnv
32+
),
33+
code ? builtins.getEnv "PWN_WORKSPACE_SERVICE_CODE" == "1",
34+
desktop ? builtins.getEnv "PWN_WORKSPACE_SERVICE_DESKTOP" == "1",
35+
}:
36+
let
37+
workspacePackages =
38+
if packageProfile == "minimal" then
39+
import ./runtime/workspace/packages { inherit pkgs; }
40+
else if packageProfile == "extended" then
41+
import ./runtime/workspace/packages/extended.nix { inherit pkgs desktop; }
42+
else
43+
throw "unsupported PWN_WORKSPACE_PACKAGES=${packageProfile}; expected minimal or extended";
44+
45+
workspaceServices = import ./runtime/workspace/services {
46+
inherit pkgs;
47+
inherit code desktop workspacePackages;
48+
};
49+
serviceNames = [
50+
"tty"
51+
]
52+
++ lib.optional code "code"
53+
++ lib.optional desktop "desktop";
54+
serviceProfile = lib.concatStringsSep "-" serviceNames;
55+
name =
56+
if packageProfile == "minimal" && serviceProfile == "tty" then
57+
"pwn-workspace-runtime"
58+
else
59+
"pwn-workspace-runtime-${packageProfile}-${serviceProfile}";
60+
runtime = import ./runtime/workspace {
61+
inherit
62+
pkgs
63+
name
64+
workspacePackages
65+
workspaceServices
66+
;
67+
};
68+
in
69+
{
70+
inherit runtime;
71+
summary = "packages=${packageProfile} services=${lib.concatStringsSep "," serviceNames}";
72+
};
2473
in
2574
{
2675
formatter = forAllSystems (
@@ -47,18 +96,20 @@
4796
let
4897
pkgs = import nixpkgs { inherit system; };
4998

50-
pwn-workspace-runtime = import ./runtime/workspace { inherit pkgs; };
99+
workspace = workspaceFor pkgs { };
51100
pwn-platform-runtime = import ./runtime/platform { inherit pkgs lib; };
52101

53-
pwnshop = import ./tools/pwnshop { inherit pkgs pwn-workspace-runtime; };
102+
pwnshop = import ./tools/pwnshop {
103+
inherit pkgs;
104+
pwn-workspace-runtime = workspace.runtime;
105+
};
54106
discord-feedback = import ./tools/feedback { inherit pkgs; };
55107
in
56108
{
57109
default = pwnshop;
58110
inherit
59111
discord-feedback
60112
pwn-platform-runtime
61-
pwn-workspace-runtime
62113
pwnshop
63114
;
64115
}
@@ -69,66 +120,79 @@
69120
let
70121
pkgs = import nixpkgs { inherit system; };
71122

72-
pwn-workspace-runtime = import ./runtime/workspace { inherit pkgs; };
123+
workspace = workspaceFor pkgs { };
124+
fullWorkspace = workspaceFor pkgs {
125+
packageProfile = "extended";
126+
code = true;
127+
desktop = true;
128+
};
73129
pwn-platform-runtime = import ./runtime/platform { inherit pkgs lib; };
74130

75-
pwnshop = import ./tools/pwnshop { inherit pkgs pwn-workspace-runtime; };
131+
pwnshop = import ./tools/pwnshop {
132+
inherit pkgs;
133+
pwn-workspace-runtime = workspace.runtime;
134+
};
76135
discord-feedback = import ./tools/feedback { inherit pkgs; };
77-
in
78-
{
79-
default = pkgs.mkShell {
80-
packages = with pkgs; [
81-
asciinema
82-
discord-feedback
83-
docker
84-
git
85-
git-crypt
86-
jq
87-
pwn-platform-runtime
88-
pwn-workspace-runtime
89-
pwnshop
90-
tomlq
91-
uv
92-
];
93-
shellHook = ''
94-
export PWN_WORKSPACE="${pwn-workspace-runtime}"
136+
mkDevShell =
137+
selectedWorkspace:
138+
pkgs.mkShell {
139+
packages = with pkgs; [
140+
asciinema
141+
discord-feedback
142+
docker
143+
git
144+
git-crypt
145+
jq
146+
pwn-platform-runtime
147+
pwnshop
148+
tomlq
149+
uv
150+
selectedWorkspace.runtime
151+
];
152+
shellHook = ''
153+
export PWN_WORKSPACE="${selectedWorkspace.runtime}"
154+
echo "workspace: ${selectedWorkspace.summary}" >&2
95155
96-
# Install the secret-test encryption pre-commit hook (idempotent,
97-
# non-destructive). Resolve the path Git actually runs the hook from
98-
# -- honoring core.hooksPath and the shared hooks dir of a linked
99-
# worktree -- and point it at the main checkout's copy so removing a
100-
# worktree can't break it.
101-
if git rev-parse --git-dir >/dev/null 2>&1; then
102-
hooks_dir="$(git config --path core.hooksPath 2>/dev/null || true)"
103-
[ -n "$hooks_dir" ] || hooks_dir="$(git rev-parse --git-path hooks)"
104-
root="$(cd "$(git rev-parse --git-common-dir)/.." && pwd)"
105-
hook="$hooks_dir/pre-commit"
106-
target="$root/tools/git-hooks/pre-commit"
107-
if [ ! -e "$hook" ] && [ ! -L "$hook" ]; then
108-
mkdir -p "$hooks_dir"
109-
ln -s "$target" "$hook"
110-
elif [ "$(readlink -f "$hook" 2>/dev/null)" != "$(readlink -f "$target" 2>/dev/null)" ]; then
111-
echo "note: $hook already exists; not overwriting (encryption hook: tools/git-hooks/pre-commit)" >&2
156+
# Install the secret-test encryption pre-commit hook (idempotent,
157+
# non-destructive). Resolve the path Git actually runs the hook from
158+
# -- honoring core.hooksPath and the shared hooks dir of a linked
159+
# worktree -- and point it at the main checkout's copy so removing a
160+
# worktree can't break it.
161+
if git rev-parse --git-dir >/dev/null 2>&1; then
162+
hooks_dir="$(git config --path core.hooksPath 2>/dev/null || true)"
163+
[ -n "$hooks_dir" ] || hooks_dir="$(git rev-parse --git-path hooks)"
164+
root="$(cd "$(git rev-parse --git-common-dir)/.." && pwd)"
165+
hook="$hooks_dir/pre-commit"
166+
target="$root/tools/git-hooks/pre-commit"
167+
if [ ! -e "$hook" ] && [ ! -L "$hook" ]; then
168+
mkdir -p "$hooks_dir"
169+
ln -s "$target" "$hook"
170+
elif [ "$(readlink -f "$hook" 2>/dev/null)" != "$(readlink -f "$target" 2>/dev/null)" ]; then
171+
echo "note: $hook already exists; not overwriting (encryption hook: tools/git-hooks/pre-commit)" >&2
172+
fi
112173
fi
113-
fi
114174
115-
sudo=
116-
if [ "$(id -u)" -ne 0 ]; then
117-
if command -v sudo >/dev/null 2>&1; then
118-
sudo=sudo
119-
else
120-
echo "error: cannot start the challenge runtime without root privileges" >&2
121-
return 1
175+
sudo=
176+
if [ "$(id -u)" -ne 0 ]; then
177+
if command -v sudo >/dev/null 2>&1; then
178+
sudo=sudo
179+
else
180+
echo "error: cannot start the challenge runtime without root privileges" >&2
181+
return 1
182+
fi
122183
fi
123-
fi
124184
125-
if ! runtime_environment="$($sudo ${lib.getExe pwn-platform-runtime})"; then
126-
echo "error: failed to start the challenge runtime" >&2
127-
return 1
128-
fi
129-
eval "$runtime_environment"
130-
'';
131-
};
185+
if ! runtime_environment="$($sudo ${lib.getExe pwn-platform-runtime})"; then
186+
echo "error: failed to start the challenge runtime" >&2
187+
return 1
188+
fi
189+
eval "$runtime_environment"
190+
'';
191+
};
192+
in
193+
{
194+
default = mkDevShell workspace;
195+
full = mkDevShell fullWorkspace;
132196
}
133197
);
134198
};

0 commit comments

Comments
 (0)