@claudinite/cli 0.0.0 → 1.61005.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD_PARTY_LICENSES +124 -0
- package/launch +357 -0
- package/manifest.json +9 -9
- package/manifest.sig.json +7 -0
- package/package.json +4 -3
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
The cn binaries include the following third-party Go modules, under these terms.
|
|
2
|
+
|
|
3
|
+
== github.com/BurntSushi/toml v1.6.0 ==
|
|
4
|
+
|
|
5
|
+
--- COPYING ---
|
|
6
|
+
|
|
7
|
+
The MIT License (MIT)
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2013 TOML authors
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in
|
|
19
|
+
all copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
27
|
+
THE SOFTWARE.
|
|
28
|
+
|
|
29
|
+
== github.com/dlclark/regexp2 v1.12.0 ==
|
|
30
|
+
|
|
31
|
+
--- LICENSE ---
|
|
32
|
+
|
|
33
|
+
The MIT License (MIT)
|
|
34
|
+
|
|
35
|
+
Copyright (c) Doug Clark
|
|
36
|
+
|
|
37
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
38
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
39
|
+
in the Software without restriction, including without limitation the rights
|
|
40
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
41
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
42
|
+
furnished to do so, subject to the following conditions:
|
|
43
|
+
|
|
44
|
+
The above copyright notice and this permission notice shall be included in all
|
|
45
|
+
copies or substantial portions of the Software.
|
|
46
|
+
|
|
47
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
48
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
49
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
50
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
51
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
52
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
53
|
+
SOFTWARE.
|
|
54
|
+
|
|
55
|
+
== go.yaml.in/yaml/v3 v3.0.5 ==
|
|
56
|
+
|
|
57
|
+
--- LICENSE ---
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
This project is covered by two different licenses: MIT and Apache.
|
|
61
|
+
|
|
62
|
+
#### MIT License ####
|
|
63
|
+
|
|
64
|
+
The following files were ported to Go from C files of libyaml, and thus
|
|
65
|
+
are still covered by their original MIT license, with the additional
|
|
66
|
+
copyright staring in 2011 when the project was ported over:
|
|
67
|
+
|
|
68
|
+
apic.go emitterc.go parserc.go readerc.go scannerc.go
|
|
69
|
+
writerc.go yamlh.go yamlprivateh.go
|
|
70
|
+
|
|
71
|
+
Copyright (c) 2006-2010 Kirill Simonov
|
|
72
|
+
Copyright (c) 2006-2011 Kirill Simonov
|
|
73
|
+
|
|
74
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
75
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
76
|
+
the Software without restriction, including without limitation the rights to
|
|
77
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
78
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
|
79
|
+
so, subject to the following conditions:
|
|
80
|
+
|
|
81
|
+
The above copyright notice and this permission notice shall be included in all
|
|
82
|
+
copies or substantial portions of the Software.
|
|
83
|
+
|
|
84
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
85
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
86
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
87
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
88
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
89
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
90
|
+
SOFTWARE.
|
|
91
|
+
|
|
92
|
+
### Apache License ###
|
|
93
|
+
|
|
94
|
+
All the remaining project files are covered by the Apache license:
|
|
95
|
+
|
|
96
|
+
Copyright (c) 2011-2019 Canonical Ltd
|
|
97
|
+
|
|
98
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
99
|
+
you may not use this file except in compliance with the License.
|
|
100
|
+
You may obtain a copy of the License at
|
|
101
|
+
|
|
102
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
103
|
+
|
|
104
|
+
Unless required by applicable law or agreed to in writing, software
|
|
105
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
106
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
107
|
+
See the License for the specific language governing permissions and
|
|
108
|
+
limitations under the License.
|
|
109
|
+
|
|
110
|
+
--- NOTICE ---
|
|
111
|
+
|
|
112
|
+
Copyright 2011-2016 Canonical Ltd.
|
|
113
|
+
|
|
114
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
115
|
+
you may not use this file except in compliance with the License.
|
|
116
|
+
You may obtain a copy of the License at
|
|
117
|
+
|
|
118
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
119
|
+
|
|
120
|
+
Unless required by applicable law or agreed to in writing, software
|
|
121
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
122
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
123
|
+
See the License for the specific language governing permissions and
|
|
124
|
+
limitations under the License.
|
package/launch
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Claudinite launcher. A member checks this file in as .claudinite/launch,
|
|
3
|
+
# unchanged; only the engine update replaces it.
|
|
4
|
+
#
|
|
5
|
+
# sh .claudinite/launch <cn arguments> fetch, verify and cache the pinned engine, then run it
|
|
6
|
+
# sh .claudinite/launch env install fetch, verify and cache only (environment pre-warm)
|
|
7
|
+
#
|
|
8
|
+
# It reads engine.version and engine.manifest from .claudinite/settings.yaml,
|
|
9
|
+
# .toml or .json, downloads that release's manifest.json and this platform's
|
|
10
|
+
# binary from the npm registry, checks the manifest against the pin and the
|
|
11
|
+
# binary against the manifest, caches the binary read-only, links
|
|
12
|
+
# .claudinite/bin/cn to it and execs it. Nothing is trusted that the pin
|
|
13
|
+
# does not cover; the registry's identity is immaterial to integrity.
|
|
14
|
+
#
|
|
15
|
+
# Only SessionStart and the Actions download step invoke it; every other hook
|
|
16
|
+
# runs .claudinite/bin/cn directly. Wired to Stop, its exit 2 on a refusal
|
|
17
|
+
# blocks the stop, and the next stop attempt hits it again, in a loop.
|
|
18
|
+
#
|
|
19
|
+
# Bootstrap: the @claudinite/cli packages carry this file as their bin, so
|
|
20
|
+
# `npx --yes @claudinite/cli init --packs ...` runs it from the package
|
|
21
|
+
# npx unpacked, through a symlink. Run with init and no settings file beside
|
|
22
|
+
# it, it takes the version and the binary's hash from the package's own
|
|
23
|
+
# manifest.json, fetches and checks the binary as above, caches it with the
|
|
24
|
+
# manifest and manifest.sig.json, and execs cn init, which verifies that
|
|
25
|
+
# signature before it writes anything. Windows is not covered: npm's shim
|
|
26
|
+
# for a sh script there is the desktop work.
|
|
27
|
+
#
|
|
28
|
+
# CLAUDINITE_REGISTRY overrides the registry and CLAUDINITE_MAX_DOWNLOAD_BYTES
|
|
29
|
+
# the download size cap; both exist for tests and the rehearsal.
|
|
30
|
+
set -u
|
|
31
|
+
|
|
32
|
+
registry=${CLAUDINITE_REGISTRY:-https://registry.npmjs.org}
|
|
33
|
+
max_bytes=${CLAUDINITE_MAX_DOWNLOAD_BYTES:-67108864}
|
|
34
|
+
|
|
35
|
+
if [ "${GITHUB_ACTIONS:-}" = true ]; then
|
|
36
|
+
context=actions
|
|
37
|
+
elif [ "${1:-}" = hook ] && [ "${2:-}" = session-start ]; then
|
|
38
|
+
context=session-start
|
|
39
|
+
elif [ "${1:-}" = hook ]; then
|
|
40
|
+
context=guard
|
|
41
|
+
else
|
|
42
|
+
context="command"
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
tmp=
|
|
46
|
+
cleanup() {
|
|
47
|
+
if [ -n "$tmp" ]; then
|
|
48
|
+
chmod -R u+w "$tmp" 2>/dev/null
|
|
49
|
+
rm -rf "$tmp"
|
|
50
|
+
tmp=
|
|
51
|
+
fi
|
|
52
|
+
}
|
|
53
|
+
trap cleanup EXIT
|
|
54
|
+
trap 'cleanup; exit 1' HUP INT TERM
|
|
55
|
+
|
|
56
|
+
say() {
|
|
57
|
+
printf 'claudinite launch: %s\n' "$*" >&2
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# A configuration or integrity failure: the engine never runs.
|
|
61
|
+
refuse() {
|
|
62
|
+
cleanup
|
|
63
|
+
say "$1"
|
|
64
|
+
case $context in
|
|
65
|
+
session-start)
|
|
66
|
+
printf 'Claudinite refused to run its engine: %s: stop and ask the person before continuing.\n' "$1"
|
|
67
|
+
exit 0 ;;
|
|
68
|
+
guard) exit 2 ;;
|
|
69
|
+
*) exit 1 ;;
|
|
70
|
+
esac
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# The registry could not be reached; nothing verified is cached.
|
|
74
|
+
unreachable() {
|
|
75
|
+
cleanup
|
|
76
|
+
case $context in
|
|
77
|
+
session-start)
|
|
78
|
+
say "could not fetch $1"
|
|
79
|
+
printf 'Claudinite could not fetch its engine from %s: stop and ask the person before continuing.\n' "$1"
|
|
80
|
+
exit 0 ;;
|
|
81
|
+
guard)
|
|
82
|
+
say "could not fetch the engine from $1; continuing without it, and SessionStart will say so again"
|
|
83
|
+
exit 0 ;;
|
|
84
|
+
*)
|
|
85
|
+
say "could not fetch the engine from $1"
|
|
86
|
+
exit 1 ;;
|
|
87
|
+
esac
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
matches() {
|
|
91
|
+
printf '%s\n' "$1" | grep -Eqx "$2"
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# Step 1: the pin, from exactly one settings file.
|
|
95
|
+
|
|
96
|
+
here=$(cd "$(dirname "$0")" && pwd) || refuse "cannot locate the .claudinite folder"
|
|
97
|
+
format=
|
|
98
|
+
count=0
|
|
99
|
+
for ext in yaml toml json; do
|
|
100
|
+
if [ -f "$here/settings.$ext" ]; then
|
|
101
|
+
format=$ext
|
|
102
|
+
count=$((count + 1))
|
|
103
|
+
fi
|
|
104
|
+
done
|
|
105
|
+
|
|
106
|
+
# The bootstrap reads the package npx unpacked: resolve the bin symlink.
|
|
107
|
+
bootstrap=
|
|
108
|
+
if [ "$count" -eq 0 ] && [ "${1:-}" = init ]; then
|
|
109
|
+
self=$0
|
|
110
|
+
while [ -L "$self" ]; do
|
|
111
|
+
link=$(readlink "$self") || break
|
|
112
|
+
case $link in
|
|
113
|
+
/*) self=$link ;;
|
|
114
|
+
*) self=$(dirname "$self")/$link ;;
|
|
115
|
+
esac
|
|
116
|
+
done
|
|
117
|
+
pkgdir=$(cd "$(dirname "$self")" && pwd) || refuse "cannot locate the package folder"
|
|
118
|
+
if [ -f "$pkgdir/manifest.json" ] && [ -f "$pkgdir/package.json" ]; then
|
|
119
|
+
bootstrap=1
|
|
120
|
+
fi
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
if [ -n "$bootstrap" ]; then
|
|
124
|
+
settings=$pkgdir/manifest.json
|
|
125
|
+
[ -f "$pkgdir/manifest.sig.json" ] || refuse "$pkgdir holds no manifest.sig.json, and cn init never runs from an unsigned manifest"
|
|
126
|
+
else
|
|
127
|
+
[ "$count" -eq 1 ] || refuse "exactly one of .claudinite/settings.yaml, .claudinite/settings.toml or .claudinite/settings.json must exist, found $count"
|
|
128
|
+
settings=$here/settings.$format
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
if [ "$format" = json ] && [ -z "$bootstrap" ]; then
|
|
132
|
+
engines=$(tr -d '\r\n' < "$settings" | grep -o '"engine"[[:blank:]]*:' | wc -l | tr -d ' ')
|
|
133
|
+
[ "$engines" -eq 1 ] || refuse "$settings must hold exactly one \"engine\" object, found $engines"
|
|
134
|
+
fi
|
|
135
|
+
|
|
136
|
+
# The lines of the engine block, one key per line. No parser: the values the
|
|
137
|
+
# launcher needs are plain quoted strings, read with a strict pattern.
|
|
138
|
+
engine_block() {
|
|
139
|
+
case $format in
|
|
140
|
+
yaml) awk '/^engine:[ \t]*$/ { inb = 1; next } inb && /^[^ \t]/ { inb = 0 } inb { print }' "$settings" ;;
|
|
141
|
+
toml) awk '/^\[engine\][ \t]*$/ { inb = 1; next } inb && /^[ \t]*\[/ { inb = 0 } inb { print }' "$settings" ;;
|
|
142
|
+
json) tr -d '\r\n' < "$settings" | sed -n 's/.*"engine"[[:blank:]]*:[[:blank:]]*{\([^{}]*\)}.*/\1/p' | tr ',' '\n' ;;
|
|
143
|
+
esac
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
# engine_value KEY: the key's quoted string, or empty when the key is absent.
|
|
147
|
+
# A key present twice, or not holding a plain quoted string, is refused.
|
|
148
|
+
engine_value() {
|
|
149
|
+
case $format in toml) sep='=' ;; *) sep=':' ;; esac
|
|
150
|
+
lines=$(engine_block | grep -E "^[[:blank:]]*\"?$1\"?[[:blank:]]*${sep}")
|
|
151
|
+
[ -z "$lines" ] && return 0
|
|
152
|
+
[ "$(printf '%s\n' "$lines" | wc -l | tr -d ' ')" -eq 1 ] || { echo "duplicate"; return 0; }
|
|
153
|
+
value=$(printf '%s\n' "$lines" | sed -n "s/^[[:blank:]]*\"\{0,1\}$1\"\{0,1\}[[:blank:]]*${sep}[[:blank:]]*\"\([^\"]*\)\"[[:blank:]]*\$/\1/p")
|
|
154
|
+
[ -n "$value" ] || value=malformed
|
|
155
|
+
printf '%s\n' "$value"
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if [ -n "$bootstrap" ]; then
|
|
159
|
+
# The version and package as the package npx unpacked names them; the
|
|
160
|
+
# manifest's own hash stands in for the pin.
|
|
161
|
+
version=$(sed -n 's/^ *"version": *"\([0-9]*\.[0-9]*\.[0-9]*\)",\{0,1\}$/\1/p' "$pkgdir/manifest.json" | head -n 1)
|
|
162
|
+
package=$(sed -n 's/^ *"name": *"\(@claudinite\/cli[-a-z]*\)",\{0,1\}$/\1/p' "$pkgdir/package.json" | head -n 1)
|
|
163
|
+
matches "$version" '[0-9]+\.[0-9]+\.[0-9]+' || refuse "$pkgdir/manifest.json names no version"
|
|
164
|
+
matches "$package" '@claudinite/cli(-rc)?' \
|
|
165
|
+
|| refuse "$pkgdir/package.json must name \"@claudinite/cli\" or \"@claudinite/cli-rc\""
|
|
166
|
+
else
|
|
167
|
+
version=$(engine_value version)
|
|
168
|
+
manifest_pin=$(engine_value manifest)
|
|
169
|
+
package=$(engine_value package)
|
|
170
|
+
[ -n "$package" ] || package=@claudinite/cli
|
|
171
|
+
|
|
172
|
+
matches "$version" '[0-9]+\.[0-9]+\.[0-9]+' \
|
|
173
|
+
|| refuse "engine.version in $settings must be a quoted version like \"1.60928.1\""
|
|
174
|
+
matches "$manifest_pin" 'sha512-[A-Za-z0-9+/]{86}==' \
|
|
175
|
+
|| refuse "engine.manifest in $settings must be a quoted sha512-... integrity string"
|
|
176
|
+
matches "$package" '@claudinite/cli(-rc)?' \
|
|
177
|
+
|| refuse "engine.package in $settings must be \"@claudinite/cli\" or \"@claudinite/cli-rc\""
|
|
178
|
+
fi
|
|
179
|
+
|
|
180
|
+
case $(uname -s) in
|
|
181
|
+
Linux) os=linux ;;
|
|
182
|
+
Darwin) os=darwin ;;
|
|
183
|
+
MINGW*|MSYS*|CYGWIN*) os=windows ;;
|
|
184
|
+
*) refuse "unsupported operating system $(uname -s)" ;;
|
|
185
|
+
esac
|
|
186
|
+
case $(uname -m) in
|
|
187
|
+
x86_64|amd64) arch=x64 ;;
|
|
188
|
+
aarch64|arm64) arch=arm64 ;;
|
|
189
|
+
*) refuse "unsupported processor $(uname -m)" ;;
|
|
190
|
+
esac
|
|
191
|
+
bin=cn
|
|
192
|
+
bin_re=cn
|
|
193
|
+
if [ "$os" = windows ]; then
|
|
194
|
+
[ "$arch" = x64 ] || refuse "unsupported platform windows-$arch"
|
|
195
|
+
bin=cn.exe
|
|
196
|
+
bin_re='cn\.exe'
|
|
197
|
+
fi
|
|
198
|
+
platform=$os-$arch
|
|
199
|
+
|
|
200
|
+
if command -v sha256sum >/dev/null 2>&1; then
|
|
201
|
+
sha256() { sha256sum < "$1" | cut -d' ' -f1; }
|
|
202
|
+
sha512() { sha512sum < "$1" | cut -d' ' -f1; }
|
|
203
|
+
elif command -v shasum >/dev/null 2>&1; then
|
|
204
|
+
sha256() { shasum -a 256 < "$1" | cut -d' ' -f1; }
|
|
205
|
+
sha512() { shasum -a 512 < "$1" | cut -d' ' -f1; }
|
|
206
|
+
elif command -v openssl >/dev/null 2>&1; then
|
|
207
|
+
sha256() { openssl dgst -sha256 < "$1" | sed 's/.*= *//'; }
|
|
208
|
+
sha512() { openssl dgst -sha512 < "$1" | sed 's/.*= *//'; }
|
|
209
|
+
else
|
|
210
|
+
refuse "no SHA-256 tool found (sha256sum, shasum or openssl)"
|
|
211
|
+
fi
|
|
212
|
+
for tool in curl tar; do
|
|
213
|
+
command -v "$tool" >/dev/null 2>&1 || refuse "$tool is not installed; the launcher needs it to fetch the engine"
|
|
214
|
+
done
|
|
215
|
+
|
|
216
|
+
# The pin's SHA-512 as lowercase hex, to compare with the hash tools' output;
|
|
217
|
+
# the bootstrap's pin is the hash of the manifest npx unpacked.
|
|
218
|
+
if [ -n "$bootstrap" ]; then
|
|
219
|
+
pin_hex=$(sha512 "$pkgdir/manifest.json")
|
|
220
|
+
else
|
|
221
|
+
pin_hex=$(printf '%s\n' "${manifest_pin#sha512-}" | awk '
|
|
222
|
+
BEGIN {
|
|
223
|
+
a = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
|
224
|
+
for (i = 0; i < 64; i++) v[substr(a, i + 1, 1)] = i
|
|
225
|
+
h = "0123456789abcdef"
|
|
226
|
+
}
|
|
227
|
+
{
|
|
228
|
+
bits = 0; nb = 0; out = ""
|
|
229
|
+
for (i = 1; i <= length($0); i++) {
|
|
230
|
+
c = substr($0, i, 1)
|
|
231
|
+
if (c == "=") break
|
|
232
|
+
bits = bits * 64 + v[c]; nb += 6
|
|
233
|
+
if (nb >= 8) {
|
|
234
|
+
nb -= 8; p = 2 ^ nb
|
|
235
|
+
byte = int(bits / p); bits -= byte * p
|
|
236
|
+
out = out substr(h, int(byte / 16) + 1, 1) substr(h, byte % 16 + 1, 1)
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
print out
|
|
240
|
+
}')
|
|
241
|
+
fi
|
|
242
|
+
|
|
243
|
+
# This platform's SHA-256 from a manifest.json whose hash matched the pin.
|
|
244
|
+
manifest_entry() {
|
|
245
|
+
sed -n "s/^ *\"$platform\": {\"file\": \"$bin_re\", \"sha256\": \"\([0-9a-f]\{64\}\)\", \"size\": [0-9]*},\{0,1\}\$/\1/p" "$1"
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
# Step 2: the cache, re-hashed on every run.
|
|
249
|
+
|
|
250
|
+
if [ -z "${XDG_CACHE_HOME:-}" ] && [ -z "${HOME:-}" ]; then
|
|
251
|
+
refuse "HOME is not set, so there is no cache folder (set HOME or XDG_CACHE_HOME)"
|
|
252
|
+
fi
|
|
253
|
+
cache_root=${XDG_CACHE_HOME:-$HOME/.cache}/claudinite
|
|
254
|
+
vdir=$cache_root/$version
|
|
255
|
+
|
|
256
|
+
private_dir() {
|
|
257
|
+
if [ ! -d "$1" ]; then
|
|
258
|
+
(umask 077 && mkdir -p "$1") || refuse "cannot create the cache directory $1"
|
|
259
|
+
fi
|
|
260
|
+
[ -L "$1" ] && refuse "the cache directory $1 is a symbolic link"
|
|
261
|
+
[ "$os" = windows ] && return 0
|
|
262
|
+
# shellcheck disable=SC2012 # ls -ldn is the portable way to read mode and uid
|
|
263
|
+
set -- "$1" "$(ls -ldn "$1" | awk '{ print $1 " " $3 }')"
|
|
264
|
+
case $2 in
|
|
265
|
+
"drwx------ $(id -u)"|"drwx------. $(id -u)"|"drwx------+ $(id -u)"|"drwx------@ $(id -u)") ;;
|
|
266
|
+
*) refuse "the cache directory $1 must be mode 0700 and owned by you (found ${2% *})" ;;
|
|
267
|
+
esac
|
|
268
|
+
}
|
|
269
|
+
private_dir "$cache_root"
|
|
270
|
+
private_dir "$vdir"
|
|
271
|
+
|
|
272
|
+
cached_ok() {
|
|
273
|
+
[ -f "$vdir/manifest.json" ] && [ -f "$vdir/$bin" ] || return 1
|
|
274
|
+
[ "$(sha512 "$vdir/manifest.json")" = "$pin_hex" ] || return 1
|
|
275
|
+
want=$(manifest_entry "$vdir/manifest.json")
|
|
276
|
+
[ -n "$want" ] && [ "$(sha256 "$vdir/$bin")" = "$want" ]
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if ! cached_ok; then
|
|
280
|
+
chmod u+w "$vdir/manifest.json" "$vdir/$bin" 2>/dev/null
|
|
281
|
+
rm -f "$vdir/manifest.json" "$vdir/$bin"
|
|
282
|
+
|
|
283
|
+
# Step 3: download by exact tarball URL, HTTPS only, with a size cap.
|
|
284
|
+
|
|
285
|
+
matches "$max_bytes" '[0-9]+' || refuse "CLAUDINITE_MAX_DOWNLOAD_BYTES must be a number"
|
|
286
|
+
# A whole transfer may take as long as the cap at about 220 kB/s, and never
|
|
287
|
+
# less than 30 s: the 64 MiB default allows about 300 s. --max-filesize
|
|
288
|
+
# bounds only the compressed size, so the wall clock is what stops a
|
|
289
|
+
# registry that stalls or trickles.
|
|
290
|
+
max_time=$((max_bytes / 220000))
|
|
291
|
+
[ "$max_time" -ge 30 ] || max_time=30
|
|
292
|
+
tmp=$(mktemp -d "$vdir/.download.XXXXXX") || refuse "cannot create a temporary folder in $vdir"
|
|
293
|
+
|
|
294
|
+
fetch() {
|
|
295
|
+
curl --proto =https --proto-redir =https --tlsv1.2 --fail --silent --show-error --location \
|
|
296
|
+
--connect-timeout 20 --max-time "$max_time" --max-filesize "$max_bytes" --output "$2" "$1" < /dev/null
|
|
297
|
+
status=$?
|
|
298
|
+
if [ "$status" -eq 63 ]; then
|
|
299
|
+
refuse "$1 is larger than the $max_bytes-byte download cap"
|
|
300
|
+
elif [ "$status" -ne 0 ]; then
|
|
301
|
+
unreachable "$1"
|
|
302
|
+
fi
|
|
303
|
+
size=$(wc -c < "$2" | tr -d ' ')
|
|
304
|
+
[ "$size" -le "$max_bytes" ] || refuse "$1 is larger than the $max_bytes-byte download cap"
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
name=${package#@claudinite/}
|
|
308
|
+
manifest_url=$registry/$package/-/$name-$version.tgz
|
|
309
|
+
binary_url=$registry/$package-$platform/-/$name-$platform-$version.tgz
|
|
310
|
+
|
|
311
|
+
fetch "$manifest_url" "$tmp/manifest.tgz"
|
|
312
|
+
tar -xzf "$tmp/manifest.tgz" -C "$tmp" package/manifest.json 2>/dev/null \
|
|
313
|
+
|| refuse "$manifest_url holds no package/manifest.json"
|
|
314
|
+
|
|
315
|
+
# Step 4: the manifest against the pin, the binary against the manifest.
|
|
316
|
+
|
|
317
|
+
[ "$(sha512 "$tmp/package/manifest.json")" = "$pin_hex" ] \
|
|
318
|
+
|| refuse "manifest.json of $package $version does not match the pin in $settings"
|
|
319
|
+
want=$(manifest_entry "$tmp/package/manifest.json")
|
|
320
|
+
[ -n "$want" ] || refuse "$package $version lists no binary for $platform"
|
|
321
|
+
|
|
322
|
+
mkdir "$tmp/platform" || refuse "cannot unpack into $tmp"
|
|
323
|
+
fetch "$binary_url" "$tmp/platform.tgz"
|
|
324
|
+
tar -xzf "$tmp/platform.tgz" -C "$tmp/platform" "package/bin/$bin" 2>/dev/null \
|
|
325
|
+
|| refuse "$binary_url holds no package/bin/$bin"
|
|
326
|
+
[ "$(sha256 "$tmp/platform/package/bin/$bin")" = "$want" ] \
|
|
327
|
+
|| refuse "the $platform binary of $package $version does not match its manifest entry"
|
|
328
|
+
|
|
329
|
+
if ! { chmod 0555 "$tmp/platform/package/bin/$bin" && chmod 0444 "$tmp/package/manifest.json" \
|
|
330
|
+
&& mv -f "$tmp/platform/package/bin/$bin" "$vdir/$bin" \
|
|
331
|
+
&& mv -f "$tmp/package/manifest.json" "$vdir/manifest.json"; }; then
|
|
332
|
+
refuse "cannot place the engine in $vdir"
|
|
333
|
+
fi
|
|
334
|
+
cleanup
|
|
335
|
+
fi
|
|
336
|
+
|
|
337
|
+
if [ "${1:-}" = env ] && [ "${2:-}" = install ] && [ "$#" -eq 2 ]; then
|
|
338
|
+
exit 0
|
|
339
|
+
fi
|
|
340
|
+
|
|
341
|
+
if [ -n "$bootstrap" ]; then
|
|
342
|
+
chmod u+w "$vdir/manifest.sig.json" 2>/dev/null
|
|
343
|
+
{ cp "$pkgdir/manifest.sig.json" "$vdir/.manifest.sig.json.$$" && chmod 0444 "$vdir/.manifest.sig.json.$$" \
|
|
344
|
+
&& mv -f "$vdir/.manifest.sig.json.$$" "$vdir/manifest.sig.json"; } || refuse "cannot place manifest.sig.json in $vdir"
|
|
345
|
+
exec "$vdir/$bin" "$@"
|
|
346
|
+
fi
|
|
347
|
+
|
|
348
|
+
# Step 5: link, unpack, run.
|
|
349
|
+
|
|
350
|
+
mkdir -p "$here/bin" || refuse "cannot create $here/bin"
|
|
351
|
+
if ! ln -sfn "$vdir/$bin" "$here/bin/$bin" 2>/dev/null; then
|
|
352
|
+
rm -f "$here/bin/$bin"
|
|
353
|
+
cp "$vdir/$bin" "$here/bin/$bin" || refuse "cannot link or copy the engine into $here/bin"
|
|
354
|
+
fi
|
|
355
|
+
# Unpacking the embedded runner script and SDK beside the binary is a no-op
|
|
356
|
+
# until the engine embeds them (no pack JavaScript runs yet).
|
|
357
|
+
exec "$vdir/$bin" "$@"
|
package/manifest.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"v": 1,
|
|
3
|
-
"version": "
|
|
4
|
-
"builtAt": "2026-10-
|
|
5
|
-
"commit": "
|
|
3
|
+
"version": "1.61005.3",
|
|
4
|
+
"builtAt": "2026-10-05T18:31:57Z",
|
|
5
|
+
"commit": "3ac2351",
|
|
6
6
|
"goVersion": "go1.24.13",
|
|
7
|
-
"updaterDigest": "
|
|
7
|
+
"updaterDigest": "13c58fc7dcdac425f220f5b84d2c15e9af019b5869046c664f06c45b39902702",
|
|
8
8
|
"binaries": {
|
|
9
|
-
"linux-x64": {"file": "cn", "sha256": "
|
|
10
|
-
"linux-arm64": {"file": "cn", "sha256": "
|
|
11
|
-
"darwin-x64": {"file": "cn", "sha256": "
|
|
12
|
-
"darwin-arm64": {"file": "cn", "sha256": "
|
|
13
|
-
"windows-x64": {"file": "cn.exe", "sha256": "
|
|
9
|
+
"linux-x64": {"file": "cn", "sha256": "e4be04505e5fff899a8eb8416d94c5f847ecbf043874f0143f08f0748dc25009", "size": 11743416},
|
|
10
|
+
"linux-arm64": {"file": "cn", "sha256": "8763455725077581879875143ec70433bdc83c0b87393cdf6cac6dc8cff34108", "size": 10879160},
|
|
11
|
+
"darwin-x64": {"file": "cn", "sha256": "3ff3c2e1eca553b9cf2c64729a2bca7944768045d8f411536a4b31be045111cd", "size": 11988416},
|
|
12
|
+
"darwin-arm64": {"file": "cn", "sha256": "94fe262c147cbd0001f6c6226ad76d8f701c468bf23d273a0a4fad7a186b3376", "size": 11091218},
|
|
13
|
+
"windows-x64": {"file": "cn.exe", "sha256": "0579a6e0b7853fe4eab6e54be70d53e0551398732a0cee0e3d8f2b3dd4409264", "size": 12019712}
|
|
14
14
|
},
|
|
15
15
|
"testedPacks": {}
|
|
16
16
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"certificate": {
|
|
3
|
+
"payload": "eyJ2IjoxLCJrZXlJZCI6ImM3NzQwNWM2ZDA4NzExODYiLCJwdWJsaWNLZXkiOiI0UHlTQzRTbG5MakJ1cVY2Qll4eU9XWUtLOWkzV295NkZCQ1ZNckF6clRzIiwidXNlIjoibWFuaWZlc3QiLCJpc3N1ZXIiOiJlYTg1ZjM1NDIxZjM3NWZjIiwibm90QmVmb3JlIjoiMjAyNi0xMC0wM1QxNjozNjozN1oiLCJub3RBZnRlciI6IjIwMjctMTAtMDNUMTY6MzY6MzdaIn0",
|
|
4
|
+
"signature": "ex4GNEE3PIUj3Ue6X2TZnbB5E6G-DVrGNaYdvI13NuOauoJYilB_54TyAH490IS9-IZiu3BKVYpigm3uDTXSBw"
|
|
5
|
+
},
|
|
6
|
+
"signature": "pj-D8AeXayFHBJWSqOMFZKeaEf0Xz2Y0sRkgaPkA7ERgFsnvTRyKAwenli2a22N1WZa0NyW8xw3TP2mLECIWBw"
|
|
7
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claudinite/cli",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Claudinite engine release manifest",
|
|
3
|
+
"version": "1.61005.3",
|
|
4
|
+
"description": "Claudinite engine release manifest and launcher",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
|
-
"repository": "github
|
|
6
|
+
"repository": {"type": "git", "url": "git+https://github.com/missingbulb/ClaudiniteEngine.git"},
|
|
7
|
+
"bin": {"cn": "launch"}
|
|
7
8
|
}
|