Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docker/platformclaw-runtime/SKILLHUB-NOTICE.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Bundled SkillHub object images

PlatformClaw builds its SkillHub server from `iflytek/skillhub` tag `v0.2.16`, commit
`6e133c006e492dc3f468d91b21960aff1d577150`, with the approved private metadata-edit
patch in `skillhub-edit/`. The image tag is
`platformclaw-skillhub-server:6e133c006e49cb1217a0ba75`. Source archive verification,
`6e133c006e492dc3f468d91b21960aff1d577150`, with the approved private metadata and artifact-policy
patches in `skillhub-edit/`. The image tag is
`platformclaw-skillhub-server:6e133c006e496f54a14d0510`. Source archive verification,
the reviewed patch, and license provenance are recorded in that directory.
The server runtime base and unchanged bundled dependencies are pinned below:

Expand Down
38 changes: 12 additions & 26 deletions docker/platformclaw-runtime/bootstrap-skillhub.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ import { readFileSync, writeFileSync } from "node:fs";
const baseUrl = process.env.SKILLHUB_BASE_URL ?? "http://skillhub.platformclaw.local:8080";
const passwordFile = process.env.SKILLHUB_BOOTSTRAP_PASSWORD_FILE;
const username = "platformclaw-bootstrap";
if (!passwordFile) throw new Error("SKILLHUB_BOOTSTRAP_PASSWORD_FILE is required");
if (!passwordFile) {
throw new Error("SKILLHUB_BOOTSTRAP_PASSWORD_FILE is required");
}

const cookies = new Map();
function absorbCookies(response) {
for (const value of response.headers.getSetCookie()) {
const pair = value.split(";", 1)[0];
const separator = pair.indexOf("=");
if (separator > 0) cookies.set(pair.slice(0, separator), pair.slice(separator + 1));
if (separator > 0) {
cookies.set(pair.slice(0, separator), pair.slice(separator + 1));
}
}
}

Expand All @@ -23,7 +27,9 @@ async function request(path, init = {}) {
}
if (init.method && init.method !== "GET") {
const csrf = cookies.get("XSRF-TOKEN");
if (!csrf) throw new Error("SkillHub did not issue a CSRF cookie");
if (!csrf) {
throw new Error("SkillHub did not issue a CSRF cookie");
}
headers.set("x-xsrf-token", decodeURIComponent(csrf));
}
const response = await fetch(new URL(path, baseUrl), { ...init, headers });
Expand All @@ -46,28 +52,6 @@ await request("/api/v1/auth/direct/login", {
}),
});

const configuredNamespaces = (process.env.SKILLHUB_NAMESPACES ?? "")
.split(",")
.map((policy) => policy.split("=", 1)[0].trim().toLowerCase())
.filter(Boolean);
const existing = await request("/api/v1/namespaces?size=200");
const existingSlugs = new Set(existing?.data?.items?.map((item) => item.slug) ?? []);
for (const slug of configuredNamespaces) {
if (!/^[a-z0-9][a-z0-9._-]{1,63}$/u.test(slug)) {
throw new Error(`Invalid configured SkillHub namespace: ${slug}`);
}
if (slug === "global" || existingSlugs.has(slug)) continue;
await request("/api/v1/namespaces", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
slug,
displayName: slug,
description: "PlatformClaw managed namespace",
}),
});
}

if (process.env.SKILLHUB_CREATE_TOKEN === "true") {
const created = await request("/api/v1/tokens", {
method: "POST",
Expand All @@ -82,6 +66,8 @@ if (process.env.SKILLHUB_CREATE_TOKEN === "true") {
throw new Error("SkillHub returned no API token");
}
const outputFile = process.env.SKILLHUB_TOKEN_OUTPUT_FILE;
if (!outputFile) throw new Error("SKILLHUB_TOKEN_OUTPUT_FILE is required");
if (!outputFile) {
throw new Error("SKILLHUB_TOKEN_OUTPUT_FILE is required");
}
writeFileSync(outputFile, `${token}\n`, { mode: 0o600 });
}
5 changes: 2 additions & 3 deletions docker/platformclaw-runtime/compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ services:
PLATFORMCLAW_SKILL_HUB_BOOTSTRAP_PASSWORD_FILE: ${PLATFORMCLAW_SKILL_HUB_BOOTSTRAP_PASSWORD_FILE:-}
# Retired value is passed through only so the loader can emit its migration error.
PLATFORMCLAW_SKILL_HUB_PRIMARY_ADMIN_ID: ${PLATFORMCLAW_SKILL_HUB_PRIMARY_ADMIN_ID:-}
PLATFORMCLAW_SKILL_HUB_NAMESPACES: ${PLATFORMCLAW_SKILL_HUB_NAMESPACES:-}
PLATFORMCLAW_SKILL_HUB_MAX_PACKAGE_BYTES: ${PLATFORMCLAW_SKILL_HUB_MAX_PACKAGE_BYTES:-524288000}
PLATFORMCLAW_EMPLOYEE_AUTH_LOGIN_URL: ${PLATFORMCLAW_EMPLOYEE_AUTH_LOGIN_URL:?set PLATFORMCLAW_EMPLOYEE_AUTH_LOGIN_URL}
PLATFORMCLAW_EMPLOYEE_AUTH_ADSSO_URL: ${PLATFORMCLAW_EMPLOYEE_AUTH_ADSSO_URL:?set PLATFORMCLAW_EMPLOYEE_AUTH_ADSSO_URL}
Expand Down Expand Up @@ -227,7 +226,7 @@ services:

skillhub-storage-init:
profiles: [skillhub]
image: ${PLATFORMCLAW_SKILL_HUB_SERVER_IMAGE:-platformclaw-skillhub-server:6e133c006e49cb1217a0ba75}
image: ${PLATFORMCLAW_SKILL_HUB_SERVER_IMAGE:-platformclaw-skillhub-server:6e133c006e496f54a14d0510}
pull_policy: never
user: "0:0"
network_mode: none
Expand Down Expand Up @@ -259,7 +258,7 @@ services:

skillhub-server:
profiles: [skillhub]
image: ${PLATFORMCLAW_SKILL_HUB_SERVER_IMAGE:-platformclaw-skillhub-server:6e133c006e49cb1217a0ba75}
image: ${PLATFORMCLAW_SKILL_HUB_SERVER_IMAGE:-platformclaw-skillhub-server:6e133c006e496f54a14d0510}
pull_policy: never
depends_on:
skillhub-postgres:
Expand Down
3 changes: 1 addition & 2 deletions docker/platformclaw-runtime/deployment.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ PLATFORMCLAW_SANDBOX_IMAGE=platformclaw-sandbox:<sha12>
# The launcher appends this heap option to existing NODE_OPTIONS.
PLATFORMCLAW_GATEWAY_MAX_OLD_SPACE_SIZE=8192
PLATFORMCLAW_SKILL_HUB_ENABLED=true
PLATFORMCLAW_SKILL_HUB_SERVER_IMAGE=platformclaw-skillhub-server:6e133c006e49cb1217a0ba75
PLATFORMCLAW_SKILL_HUB_SERVER_IMAGE=platformclaw-skillhub-server:6e133c006e496f54a14d0510
PLATFORMCLAW_SKILL_HUB_SCANNER_IMAGE=platformclaw-skillhub-scanner:6e133c006e49
PLATFORMCLAW_SKILL_HUB_POSTGRES_IMAGE=platformclaw-skillhub-postgres:44c4ee9810ef
PLATFORMCLAW_SKILL_HUB_REDIS_IMAGE=platformclaw-skillhub-redis:e7723ff73d96
Expand Down Expand Up @@ -34,7 +34,6 @@ PLATFORMCLAW_KNOX_CDEP_URL=http://<cdep-host>:8080/api/v1/platformclaw/knox/outb
PLATFORMCLAW_SKILL_HUB_URL=http://skillhub.platformclaw.local:8080
PLATFORMCLAW_SKILL_HUB_TOKEN_FILE=/run/secrets/platformclaw_skill_hub_token
PLATFORMCLAW_SKILL_HUB_BOOTSTRAP_PASSWORD_FILE=/run/secrets/platformclaw_skill_hub_bootstrap_password
PLATFORMCLAW_SKILL_HUB_NAMESPACES=global=all
PLATFORMCLAW_SKILL_HUB_MAX_PACKAGE_BYTES=524288000

# Optional public web relay endpoints. Leave blank for normal direct/provider behavior.
Expand Down
11 changes: 5 additions & 6 deletions docker/platformclaw-runtime/platformclaw-deploy
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,6 @@ bootstrap_skillhub() {
--read-only --user "$runtime_uid:$runtime_gid" --cap-drop ALL \
--security-opt no-new-privileges:true \
--env SKILLHUB_BASE_URL=http://skillhub.platformclaw.local:8080 \
--env "SKILLHUB_NAMESPACES=$(read_env_value PLATFORMCLAW_SKILL_HUB_NAMESPACES)" \
--env "SKILLHUB_CREATE_TOKEN=$create_token" \
--env SKILLHUB_BOOTSTRAP_PASSWORD_FILE=/run/secrets/bootstrap-password \
--env SKILLHUB_TOKEN_OUTPUT_FILE=/run/secrets/control-token \
Expand All @@ -686,7 +685,7 @@ bootstrap_skillhub() {
: >"$token_file"
chmod 0600 "$token_file"
fi
echo "SkillHub token/namespace bootstrap failed; Hub remains internal and Control was not started." >&2
echo "SkillHub token bootstrap failed; Hub remains internal and Control was not started." >&2
exit 1
fi
if [[ "$create_token" == "true" ]]; then
Expand Down Expand Up @@ -779,9 +778,9 @@ reconcile_skillhub_environment() {
local key
local temporary
local value
if grep -Eq '^PLATFORMCLAW_SKILL_HUB_(TOKEN|POSTGRES_PASSWORD|COOKIE|BOOTSTRAP_PASSWORD)_SECRET_FILE=' "$env_file"; then
if grep -Eq '^PLATFORMCLAW_SKILL_HUB_((TOKEN|POSTGRES_PASSWORD|COOKIE|BOOTSTRAP_PASSWORD)_SECRET_FILE|NAMESPACES)=' "$env_file"; then
temporary="$(mktemp "$deploy_root/.deployment.env.XXXXXX")"
grep -Ev '^PLATFORMCLAW_SKILL_HUB_(TOKEN|POSTGRES_PASSWORD|COOKIE|BOOTSTRAP_PASSWORD)_SECRET_FILE=' \
grep -Ev '^PLATFORMCLAW_SKILL_HUB_((TOKEN|POSTGRES_PASSWORD|COOKIE|BOOTSTRAP_PASSWORD)_SECRET_FILE|NAMESPACES)=' \
"$env_file" >"$temporary"
chmod 0600 "$temporary"
mv -f "$temporary" "$env_file"
Expand All @@ -799,7 +798,7 @@ reconcile_skillhub_environment() {
for key in PLATFORMCLAW_SKILL_HUB_SERVER_IMAGE PLATFORMCLAW_SKILL_HUB_SCANNER_IMAGE \
PLATFORMCLAW_SKILL_HUB_POSTGRES_IMAGE PLATFORMCLAW_SKILL_HUB_REDIS_IMAGE \
PLATFORMCLAW_SKILL_HUB_URL PLATFORMCLAW_SKILL_HUB_TOKEN_FILE \
PLATFORMCLAW_SKILL_HUB_BOOTSTRAP_PASSWORD_FILE PLATFORMCLAW_SKILL_HUB_NAMESPACES \
PLATFORMCLAW_SKILL_HUB_BOOTSTRAP_PASSWORD_FILE \
PLATFORMCLAW_SKILL_HUB_MAX_PACKAGE_BYTES; do
[[ -n "$(read_env_value "$key")" ]] && continue
value="$(read_env_value "$key" "$script_dir/deployment.env.example")"
Expand Down Expand Up @@ -904,7 +903,7 @@ validate_deployment_env() {
PLATFORMCLAW_SKILL_HUB_POSTGRES_IMAGE PLATFORMCLAW_SKILL_HUB_REDIS_IMAGE \
PLATFORMCLAW_SKILL_HUB_URL PLATFORMCLAW_SKILL_HUB_TOKEN_FILE \
PLATFORMCLAW_SKILL_HUB_BOOTSTRAP_PASSWORD_FILE \
PLATFORMCLAW_SKILL_HUB_NAMESPACES PLATFORMCLAW_SKILL_HUB_MAX_PACKAGE_BYTES; do
PLATFORMCLAW_SKILL_HUB_MAX_PACKAGE_BYTES; do
value="$(read_env_value "$key")"
[[ -n "$value" && "$value" != *'<'* && "$value" != *'>'* ]] || invalid+=("$key")
done
Expand Down
6 changes: 3 additions & 3 deletions docker/platformclaw-runtime/skillhub-edit/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ FROM maven:3.9-eclipse-temurin-21@sha256:99e61abcff91a9b1333463bd8451fb18495d6eb
WORKDIR /source
ADD --checksum=sha256:de66167863d258888316cc54875e31a96150410afa7dbfa7782ccd7fe0e3beab https://codeload.github.com/iflytek/skillhub/tar.gz/6e133c006e492dc3f468d91b21960aff1d577150 /tmp/upstream.tar.gz
RUN tar -xzf /tmp/upstream.tar.gz --strip-components=1
COPY upstream.patch upstream-tests.patch /tmp/
RUN git apply --unidiff-zero --check /tmp/upstream.patch && git apply --unidiff-zero /tmp/upstream.patch && git apply --unidiff-zero /tmp/upstream-tests.patch
COPY upstream.patch upstream-tests.patch artifact-policy.patch artifact-tests.patch /tmp/
RUN git apply --unidiff-zero --check /tmp/upstream.patch && git apply --unidiff-zero /tmp/upstream.patch && git apply --unidiff-zero /tmp/upstream-tests.patch && git apply --unidiff-zero --check /tmp/artifact-policy.patch && git apply --unidiff-zero /tmp/artifact-policy.patch && git apply --unidiff-zero /tmp/artifact-tests.patch
COPY overlay/ /source/
WORKDIR /source/server
RUN --mount=type=cache,target=/root/.m2 mvn -B -pl skillhub-app -am package -DskipTests
Expand Down Expand Up @@ -33,4 +33,4 @@ LABEL org.opencontainers.image.base.name="docker.io/library/eclipse-temurin:21.0
org.opencontainers.image.url="https://github.com/iflytek/skillhub" \
org.opencontainers.image.version="0.2.16" \
org.opencontainers.image.licenses="Apache-2.0" \
ai.platformclaw.skillhub.patch="metadata-edit-v1"
ai.platformclaw.skillhub.patch="artifact-policy-v1"
Loading
Loading