Integrate G15 submodules with Debian 13 packaging and devcontainer

This commit is contained in:
Mikhail Yevchenko committed 2026-09-07 15:44:03 +03:00
commit 795db7924b
28 files changed
+714

No files matched your search

+62
View File
@@ -0,0 +1,62 @@
#!/usr/bin/env bash
set -euo pipefail
for command in devcontainer docker node; do
command -v "$command" >/dev/null || { echo "Required command missing: $command" >&2; exit 1; }
done
workspace=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd -P)
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
devcontainer up --workspace-folder "$workspace" > "$tmp/up.json"
container=$(node -e '
const result = JSON.parse(require("fs").readFileSync(process.argv[1], "utf8"));
if (result.outcome !== "success" || !result.containerId) throw Error("CLI startup failed");
process.stdout.write(result.containerId);
' "$tmp/up.json")
docker inspect "$container" > "$tmp/inspect.json"
node - "$tmp/inspect.json" "$workspace" <<'NODE'
const fs = require('fs');
const assert = require('assert/strict');
const [container] = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
const host = container.HostConfig;
const expected = [];
const products = new Set(['c222', 'c225', 'c227', 'c22b', 'c22d', 'c22e']);
for (const entry of fs.readdirSync('/sys/bus/usb/devices')) {
const base = `/sys/bus/usb/devices/${entry}`;
const read = name => fs.readFileSync(`${base}/${name}`, 'utf8').trim();
try {
if (read('idVendor') !== '046d' || !products.has(read('idProduct'))) continue;
const bus = read('busnum'), number = read('devnum');
assert.match(bus, /^\d{1,3}$/);
assert.match(number, /^\d{1,3}$/);
const node = `/dev/bus/usb/${String(Number(bus)).padStart(3, '0')}/${String(Number(number)).padStart(3, '0')}`;
if (fs.statSync(node).isCharacterDevice()) expected.push(node);
} catch (error) {
if (error.code !== 'ENOENT') throw error;
}
}
assert.equal(container.State.Running, true, 'container must be running');
assert.equal(host.Privileged, false, 'privileged mode forbidden');
assert.notEqual(host.NetworkMode, 'host', 'host networking forbidden');
assert.deepEqual(host.DeviceCgroupRules || [], [], 'device cgroup overrides forbidden');
assert.deepEqual(host.DeviceRequests || [], [], 'additional device requests forbidden');
const devices = host.Devices || [];
assert.deepEqual(devices.map(device => device.PathOnHost).sort(), expected.sort(),
'USB mappings must match current host allowlist; reconnects may require container recreation');
for (const device of devices) {
assert.equal(device.PathInContainer, device.PathOnHost, 'device remapping forbidden');
assert.equal(device.CgroupPermissions, 'rw', 'only rw device access allowed');
}
// Only the checkout bind and the CLI's optional editor volume are permitted.
assert(container.Mounts.some(mount => mount.Type === 'bind' &&
mount.Source === process.argv[3] && mount.Destination === '/work'), 'workspace bind missing');
for (const mount of container.Mounts) {
assert((mount.Type === 'bind' && mount.Source === process.argv[3] && mount.Destination === '/work') ||
(mount.Type === 'volume' && mount.Name === 'vscode' && mount.Destination === '/vscode'),
`unexpected mount: ${mount.Source} -> ${mount.Destination}`);
}
console.log(`PASS: real Docker configuration; ${devices.length} exact allowed USB mapping(s)`);
NODE
# Expand PWD inside the container, not on the host.
# shellcheck disable=SC2016
devcontainer exec --workspace-folder "$workspace" bash -c \
'set -euo pipefail; test "$PWD" = /work; test -f .devcontainer/devcontainer.json; test ! -e /dev/uinput; printf "PASS: CLI exec and no /dev/uinput; no keyboard I/O performed\n"'