Skip to content
Open
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
80 changes: 47 additions & 33 deletions Dockerfile.demo
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,9 @@ RUN --mount=type=cache,id=cargo-registry-whisper,target=/usr/local/cargo/registr
--mount=type=cache,id=whisper-target-portable-v2,target=/build/plugins/native/whisper/target-portable \
cd plugins/native/whisper && \
cargo build --release --target-dir target-portable && \
mkdir -p /build/plugins/native && \
cp target-portable/release/libwhisper.so /build/plugins/native/
mkdir -p /build/dist/native/whisper && \
cp target-portable/release/libwhisper.so /build/dist/native/whisper/ && \
cp plugin.yml /build/dist/native/whisper/

# Download Whisper models (demo image uses a single tiny multilingual model).
# - ggml-tiny-q5_1.bin: Tiny multilingual STT (quantized)
Expand Down Expand Up @@ -211,8 +212,9 @@ RUN --mount=type=cache,id=cargo-registry-kokoro,target=/usr/local/cargo/registry
--mount=type=cache,target=/build/plugins/native/kokoro/target \
cd plugins/native/kokoro && \
RUSTFLAGS="-L /usr/local/lib" cargo build --release --target-dir target && \
mkdir -p /build/plugins/native && \
cp target/release/libkokoro.so /build/plugins/native/
mkdir -p /build/dist/native/kokoro && \
cp target/release/libkokoro.so /build/dist/native/kokoro/ && \
cp plugin.yml /build/dist/native/kokoro/

# Download Kokoro TTS models
RUN mkdir -p /build/models && \
Expand Down Expand Up @@ -255,8 +257,9 @@ RUN --mount=type=cache,id=cargo-registry-piper,target=/usr/local/cargo/registry
--mount=type=cache,target=/build/plugins/native/piper/target \
cd plugins/native/piper && \
RUSTFLAGS="-L /usr/local/lib" cargo build --release --target-dir target && \
mkdir -p /build/plugins/native && \
cp target/release/libpiper.so /build/plugins/native/
mkdir -p /build/dist/native/piper && \
cp target/release/libpiper.so /build/dist/native/piper/ && \
cp plugin.yml /build/dist/native/piper/

# Download Piper TTS models (English + Spanish for translation output)
RUN mkdir -p /build/models && \
Expand Down Expand Up @@ -312,8 +315,9 @@ RUN --mount=type=cache,id=cargo-registry-sensevoice,target=/usr/local/cargo/regi
--mount=type=cache,target=/build/plugins/native/sensevoice/target \
cd plugins/native/sensevoice && \
RUSTFLAGS="-L /usr/local/lib" cargo build --release --target-dir target && \
mkdir -p /build/plugins/native && \
cp target/release/libsensevoice.so /build/plugins/native/
mkdir -p /build/dist/native/sensevoice && \
cp target/release/libsensevoice.so /build/dist/native/sensevoice/ && \
cp plugin.yml /build/dist/native/sensevoice/

# Download SenseVoice models
RUN mkdir -p /build/models && \
Expand Down Expand Up @@ -356,8 +360,9 @@ RUN --mount=type=cache,id=cargo-registry-vad,target=/usr/local/cargo/registry \
--mount=type=cache,target=/build/plugins/native/vad/target \
cd plugins/native/vad && \
RUSTFLAGS="-L /usr/local/lib" cargo build --release --target-dir target && \
mkdir -p /build/plugins/native && \
cp target/release/libvad.so /build/plugins/native/
mkdir -p /build/dist/native/vad && \
cp target/release/libvad.so /build/dist/native/vad/ && \
cp plugin.yml /build/dist/native/vad/

# Download ten-vad model
RUN mkdir -p /build/models && \
Expand Down Expand Up @@ -397,8 +402,9 @@ RUN --mount=type=cache,id=cargo-registry-matcha,target=/usr/local/cargo/registry
--mount=type=cache,target=/build/plugins/native/matcha/target \
cd plugins/native/matcha && \
RUSTFLAGS="-L /usr/local/lib" cargo build --release --target-dir target && \
mkdir -p /build/plugins/native && \
cp target/release/libmatcha.so /build/plugins/native/
mkdir -p /build/dist/native/matcha && \
cp target/release/libmatcha.so /build/dist/native/matcha/ && \
cp plugin.yml /build/dist/native/matcha/

# Download Matcha TTS models
RUN mkdir -p /build/models && \
Expand Down Expand Up @@ -440,8 +446,9 @@ RUN --mount=type=cache,id=helsinki-cargo-registry,target=/usr/local/cargo/regist
--mount=type=cache,id=helsinki-target,target=/build/plugins/native/helsinki/target \
cd plugins/native/helsinki && \
cargo build --release --target-dir target && \
mkdir -p /build/plugins/native && \
cp target/release/libhelsinki.so /build/plugins/native/
mkdir -p /build/dist/native/helsinki && \
cp target/release/libhelsinki.so /build/dist/native/helsinki/ && \
cp plugin.yml /build/dist/native/helsinki/

# Download and convert OPUS-MT models (EN<->ES)
RUN PIP_BREAK_SYSTEM_PACKAGES=1 pip3 install --no-cache-dir \
Expand Down Expand Up @@ -482,8 +489,9 @@ RUN --mount=type=cache,id=cargo-registry-pocket-tts,target=/usr/local/cargo/regi
--mount=type=cache,id=pocket-tts-target,target=/build/plugins/native/pocket-tts/target \
cd plugins/native/pocket-tts && \
cargo build --release --target-dir target && \
mkdir -p /build/plugins/native && \
cp target/release/libpocket_tts.so /build/plugins/native/
mkdir -p /build/dist/native/pocket-tts && \
cp target/release/libpocket_tts.so /build/dist/native/pocket-tts/ && \
cp plugin.yml /build/dist/native/pocket-tts/

# Download Pocket TTS models
RUN mkdir -p /build/models && \
Expand Down Expand Up @@ -523,8 +531,9 @@ RUN --mount=type=cache,id=cargo-registry-supertonic,target=/usr/local/cargo/regi
--mount=type=cache,id=supertonic-target,target=/build/plugins/native/supertonic/target \
cd plugins/native/supertonic && \
cargo build --release --target-dir target && \
mkdir -p /build/plugins/native && \
cp target/release/libsupertonic.so /build/plugins/native/
mkdir -p /build/dist/native/supertonic && \
cp target/release/libsupertonic.so /build/dist/native/supertonic/ && \
cp plugin.yml /build/dist/native/supertonic/

# Download Supertonic models
RUN mkdir -p /build/models && \
Expand Down Expand Up @@ -562,8 +571,9 @@ RUN --mount=type=cache,id=cargo-registry-aac-encoder,target=/usr/local/cargo/reg
--mount=type=cache,id=aac-encoder-target,target=/build/plugins/native/aac-encoder/target \
cd plugins/native/aac-encoder && \
cargo build --release --target-dir target && \
mkdir -p /build/plugins/native && \
cp target/release/libaac_encoder.so /build/plugins/native/
mkdir -p /build/dist/native/aac-encoder && \
cp target/release/libaac_encoder.so /build/dist/native/aac-encoder/ && \
cp plugin.yml /build/dist/native/aac-encoder/

# Stage 14: Build Slint UI plugin
FROM rust:1.95-slim-bookworm AS slint-builder
Expand Down Expand Up @@ -595,8 +605,9 @@ RUN --mount=type=cache,id=cargo-registry-slint,target=/usr/local/cargo/registry
--mount=type=cache,id=slint-target,target=/build/plugins/native/slint/target \
cd plugins/native/slint && \
cargo build --release --target-dir target && \
mkdir -p /build/plugins/native && \
cp target/release/libslint.so /build/plugins/native/
mkdir -p /build/dist/native/slint && \
cp target/release/libslint.so /build/dist/native/slint/ && \
cp plugin.yml /build/dist/native/slint/

# Runtime stage
FROM debian:bookworm-slim
Expand Down Expand Up @@ -628,50 +639,53 @@ COPY --from=kokoro-builder /usr/local/lib/*.so* /usr/local/lib/
RUN ldconfig

# Copy whisper plugin and models
# Plugins are shipped as directory bundles (plugins/native/<id>/ with a
# plugin.yml + the .so) — the layout the loader expects; bare .so files in
# plugins/native/ are ignored.
# IMPORTANT: Use --chown=app:app on every COPY to avoid a bulk `chown -R` later
# which would duplicate every file in a new layer (~12GB waste).
COPY --chown=app:app --from=whisper-builder /build/plugins /opt/streamkit/plugins
COPY --chown=app:app --from=whisper-builder /build/dist /opt/streamkit/plugins
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: First COPY uses /build/dist (full tree) while subsequent COPYs use specific subdirectories

The whisper plugin is copied with COPY --from=whisper-builder /build/dist /opt/streamkit/plugins (line 647), which bootstraps the entire plugins/native/ tree structure. All subsequent plugins use targeted paths like COPY --from=kokoro-builder /build/dist/native/kokoro /opt/streamkit/plugins/native/kokoro (line 651). This asymmetry is intentional: the first COPY creates the native/ directory hierarchy, and subsequent COPYs merge individual plugin directories into it. If whisper were ever removed, the first plugin in the list would need to use the full-tree COPY pattern instead to create the directory structure.

Open in Devin Review (Staging)

Was this helpful? React with 👍 or 👎 to provide feedback.

Debug

Playground

COPY --chown=app:app --from=whisper-builder /build/models /opt/streamkit/models

# Copy kokoro plugin and models (merge into /opt/streamkit/plugins and /opt/streamkit/models)
COPY --chown=app:app --from=kokoro-builder /build/plugins/native/* /opt/streamkit/plugins/native/
COPY --chown=app:app --from=kokoro-builder /build/dist/native/kokoro /opt/streamkit/plugins/native/kokoro
COPY --chown=app:app --from=kokoro-builder /build/models/kokoro-multi-lang-v1_1 /opt/streamkit/models/kokoro-multi-lang-v1_1

# Copy piper plugin and models (merge into /opt/streamkit/plugins and /opt/streamkit/models)
COPY --chown=app:app --from=piper-builder /build/plugins/native/* /opt/streamkit/plugins/native/
COPY --chown=app:app --from=piper-builder /build/dist/native/piper /opt/streamkit/plugins/native/piper
COPY --chown=app:app --from=piper-builder /build/models/vits-piper-en_US-libritts_r-medium /opt/streamkit/models/vits-piper-en_US-libritts_r-medium
COPY --chown=app:app --from=piper-builder /build/models/vits-piper-es_MX-claude-high /opt/streamkit/models/vits-piper-es_MX-claude-high

# Copy sensevoice plugin and models (merge into /opt/streamkit/plugins and /opt/streamkit/models)
COPY --chown=app:app --from=sensevoice-builder /build/plugins/native/* /opt/streamkit/plugins/native/
COPY --chown=app:app --from=sensevoice-builder /build/dist/native/sensevoice /opt/streamkit/plugins/native/sensevoice
COPY --chown=app:app --from=sensevoice-builder /build/models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2025-09-09 /opt/streamkit/models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2025-09-09

# Copy helsinki plugin and models
COPY --chown=app:app --from=helsinki-builder /build/plugins/native/* /opt/streamkit/plugins/native/
COPY --chown=app:app --from=helsinki-builder /build/dist/native/helsinki /opt/streamkit/plugins/native/helsinki
COPY --chown=app:app --from=helsinki-builder /build/models/opus-mt-en-es /opt/streamkit/models/opus-mt-en-es
COPY --chown=app:app --from=helsinki-builder /build/models/opus-mt-es-en /opt/streamkit/models/opus-mt-es-en

# Copy vad plugin and model (merge into /opt/streamkit/plugins and /opt/streamkit/models)
COPY --chown=app:app --from=vad-builder /build/plugins/native/* /opt/streamkit/plugins/native/
COPY --chown=app:app --from=vad-builder /build/dist/native/vad /opt/streamkit/plugins/native/vad
COPY --chown=app:app --from=vad-builder /build/models/ten-vad.onnx /opt/streamkit/models/ten-vad.onnx

# Copy matcha plugin and models (merge into /opt/streamkit/plugins and /opt/streamkit/models)
COPY --chown=app:app --from=matcha-builder /build/plugins/native/* /opt/streamkit/plugins/native/
COPY --chown=app:app --from=matcha-builder /build/dist/native/matcha /opt/streamkit/plugins/native/matcha
COPY --chown=app:app --from=matcha-builder /build/models/matcha-icefall-en_US-ljspeech /opt/streamkit/models/matcha-icefall-en_US-ljspeech

# Copy pocket-tts plugin and models
COPY --chown=app:app --from=pocket-tts-builder /build/plugins/native/* /opt/streamkit/plugins/native/
COPY --chown=app:app --from=pocket-tts-builder /build/dist/native/pocket-tts /opt/streamkit/plugins/native/pocket-tts
COPY --chown=app:app --from=pocket-tts-builder /build/models/pocket-tts /opt/streamkit/models/pocket-tts

# Copy supertonic plugin and models
COPY --chown=app:app --from=supertonic-builder /build/plugins/native/* /opt/streamkit/plugins/native/
COPY --chown=app:app --from=supertonic-builder /build/dist/native/supertonic /opt/streamkit/plugins/native/supertonic
COPY --chown=app:app --from=supertonic-builder /build/models/supertonic-v2-onnx /opt/streamkit/models/supertonic-v2-onnx

# Copy slint plugin (no models needed)
COPY --chown=app:app --from=slint-builder /build/plugins/native/* /opt/streamkit/plugins/native/
COPY --chown=app:app --from=slint-builder /build/dist/native/slint /opt/streamkit/plugins/native/slint

# Copy aac-encoder plugin (no models needed)
COPY --chown=app:app --from=aac-encoder-builder /build/plugins/native/* /opt/streamkit/plugins/native/
COPY --chown=app:app --from=aac-encoder-builder /build/dist/native/aac-encoder /opt/streamkit/plugins/native/aac-encoder

# Copy sample pipelines + small bundled audio samples (Opus/Ogg only)
COPY --chown=app:app samples/pipelines /opt/streamkit/samples/pipelines
Expand Down
1 change: 1 addition & 0 deletions examples/speech-gateway/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Environment equivalents:
- `GATEWAY_MAX_CONCURRENCY` (default 10)
- `GATEWAY_MAX_BODY_BYTES` (default 1MB)
- `GATEWAY_MAX_TTS_TEXT_SIZE` (default 1000 characters)
- `GATEWAY_STT_MODEL` (default `models/ggml-tiny-q5_1.bin`, the Whisper model bundled in the `-demo` images; must exist on the skit backend)

## STT via curl (Ogg/Opus)

Expand Down
11 changes: 9 additions & 2 deletions examples/speech-gateway/cmd/gateway/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import (
const (
defaultSkitURL = "http://127.0.0.1:4545"
defaultListenAddr = ":8080"
// Matches the Whisper model bundled in the -demo images.
defaultSTTModel = "models/ggml-tiny-q5_1.bin"
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Default STT model changed from base.en to tiny — intentional fix, not a regression

The old hardcoded model path was models/ggml-base.en-q5_1.bin, but the demo Dockerfile (line 173) only ships ggml-tiny-q5_1.bin. The old default would silently fail at pipeline execution time on the demo image. The new default models/ggml-tiny-q5_1.bin correctly matches the bundled model. This is a bug fix for users running the gateway against the demo image.

Open in Devin Review (Staging)

Was this helpful? React with 👍 or 👎 to provide feedback.

Debug

Playground


sttPipelineYAML = `
name: stt-ogg-opus
Expand All @@ -53,7 +55,7 @@ steps:

- kind: plugin::native::whisper
params:
model_path: models/ggml-base.en-q5_1.bin
model_path: %s
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Unquoted fmt.Sprintf substitution into YAML template is safe for file paths but fragile for arbitrary strings

The model_path: %s template at examples/speech-gateway/cmd/gateway/main.go:58 is substituted via fmt.Sprintf at line 137. Because the value is unquoted YAML, a model path containing YAML-special characters (#, : , [, {, etc.) would produce invalid or misinterpreted YAML. This is not a bug because: (1) the old hardcoded value was also unquoted (model_path: models/ggml-base.en-q5_1.bin), so no regression; (2) the value comes from operator configuration (env var / CLI flag), not HTTP request input; (3) realistic model file paths never contain these characters. Wrapping in quotes (model_path: "%s") would make it more robust but would require escaping embedded quotes. The current approach is consistent with how all other YAML values in both pipeline templates are written.

Open in Devin Review (Staging)

Was this helpful? React with 👍 or 👎 to provide feedback.

Debug

Playground

language: en
vad_model_path: models/silero_vad.onnx
vad_threshold: 0.5
Expand Down Expand Up @@ -110,6 +112,7 @@ type gateway struct {
authToken string
maxBodySize int64
maxTTSTextSize int64
sttPipeline string
sem chan struct{}
}

Expand All @@ -120,6 +123,7 @@ type config struct {
maxConcurrency int
maxBodySize int64
maxTTSTextSize int64
sttModel string
}

func main() {
Expand All @@ -130,6 +134,7 @@ func main() {
authToken: cfg.authToken,
maxBodySize: cfg.maxBodySize,
maxTTSTextSize: cfg.maxTTSTextSize,
sttPipeline: fmt.Sprintf(sttPipelineYAML, cfg.sttModel),
sem: make(chan struct{}, cfg.maxConcurrency),
}

Expand Down Expand Up @@ -159,6 +164,7 @@ func loadConfig() config {
maxConc := flagInt("max-concurrency", envInt("GATEWAY_MAX_CONCURRENCY", 10), "Maximum concurrent in-flight requests")
maxBody := flagInt64("max-body-bytes", envInt64("GATEWAY_MAX_BODY_BYTES", 1*1024*1024), "Maximum request body size")
maxTTSText := flagInt64("max-tts-text-size", envInt64("GATEWAY_MAX_TTS_TEXT_SIZE", 1000), "Maximum TTS text size in characters")
sttModel := flagString("stt-model", getEnvDefault("GATEWAY_STT_MODEL", defaultSTTModel), "Whisper model path used by the STT pipeline (relative to the skit working dir)")

flag.Parse()

Expand All @@ -169,6 +175,7 @@ func loadConfig() config {
maxConcurrency: *maxConc,
maxBodySize: *maxBody,
maxTTSTextSize: *maxTTSText,
sttModel: *sttModel,
}
}

Expand Down Expand Up @@ -262,7 +269,7 @@ func (gw *gateway) handleSTT(w http.ResponseWriter, r *http.Request) {
defer release()
r.Body = http.MaxBytesReader(underlying(w), r.Body, gw.maxBodySize)
useBuffer := r.ContentLength > 0 && r.ContentLength <= gw.maxBodySize
gw.proxyMultipart(w, r, "stt", sttPipelineYAML, "media", "audio/ogg", useBuffer)
gw.proxyMultipart(w, r, "stt", gw.sttPipeline, "media", "audio/ogg", useBuffer)
}

func (gw *gateway) handleTTS(w http.ResponseWriter, r *http.Request) {
Expand Down
16 changes: 15 additions & 1 deletion examples/speech-gateway/cmd/gateway/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@

package main

import "testing"
import (
"fmt"
"strings"
"testing"
)

func TestUnwrapPacketJSON(t *testing.T) {
cases := []struct {
Expand Down Expand Up @@ -72,3 +76,13 @@ func TestIsJSONContentType(t *testing.T) {
}
}
}

func TestSTTPipelineModelTemplating(t *testing.T) {
got := fmt.Sprintf(sttPipelineYAML, defaultSTTModel)
if !strings.Contains(got, "model_path: models/ggml-tiny-q5_1.bin") {
t.Errorf("default STT pipeline missing expected model_path:\n%s", got)
}
if strings.Contains(got, "%!") {
t.Errorf("STT pipeline has unresolved format verbs:\n%s", got)
}
}
21 changes: 12 additions & 9 deletions samples/observability/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,10 @@ Notes:
metrics-instrumented gateway. The Speech Gateway dashboard row stays empty
until those metrics are present and the gateway has served traffic.
- The gateway's default STT pipeline targets a Whisper model that must exist on
the skit it talks to. The bundled `-demo` image ships `ggml-tiny-q5_1.bin`; if
the gateway points at a different model, STT through the gateway will fail
while TTS still works. The direct-to-skit traffic path (the default
the skit it talks to. The default (`models/ggml-tiny-q5_1.bin`, overridable
via `GATEWAY_STT_MODEL` / `--stt-model`) matches what the `-demo` image
ships; if the gateway points at a model that isn't present, STT through the
gateway will fail while TTS still works. The direct-to-skit traffic path (the default
`generate-traffic.sh`) avoids this by shipping its own pipelines under
`pipelines/`.

Expand All @@ -87,12 +88,14 @@ These are the sharp edges worth knowing when wiring this up yourself:
- **Pin a versioned `-demo` tag.** `latest-demo` can lag behind released
versions and predate metrics like `plugin.call.duration`, which leaves the
Plugins / ML inference row empty. This stack pins `v0.5.0-demo`.
- **Demo image plugin layout.** Current `-demo` images ship native plugins as
bare `.so` files under `plugins/native/`, but the loader expects directory
bundles (`plugins/native/<id>/` with a `plugin.yml` + the `.so`). `skit serve`
otherwise logs "no plugins found" and pipelines fail with "node kind not
found". `skit/entrypoint.sh` reassembles the expected layout at startup from
the in-repo manifests (mounted at `/repo-manifests`).
- **Demo image plugin layout.** Older `-demo` images (<= v0.5.0) ship native
plugins as bare `.so` files under `plugins/native/`, but the loader expects
directory bundles (`plugins/native/<id>/` with a `plugin.yml` + the `.so`).
`skit serve` otherwise logs "no plugins found" and pipelines fail with "node
kind not found". `skit/entrypoint.sh` reassembles the expected layout at
startup from the in-repo manifests (mounted at `/repo-manifests`); newer
images ship the bundles directly and the shim passes them through. Once the
pinned tag ships bundles, the shim can be dropped.
- **Model names must match.** Pipelines reference model files by path; the file
must actually be present in the image/`models/` dir. The pipelines under
`pipelines/` use the model names the `-demo` image actually ships.
Expand Down
22 changes: 16 additions & 6 deletions samples/observability/skit/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,34 @@
#
# SPDX-License-Identifier: MPL-2.0

# The -demo images currently ship native plugins as bare `.so` files under
# Older -demo images (<= v0.5.0) ship native plugins as bare `.so` files under
# plugins/native/, but the loader expects directory bundles
# (plugins/native/<id>/ with a plugin.yml + the .so). Without this, `skit serve`
# logs "no plugins found" and TTS/STT pipelines fail with "node kind not found".
# We assemble the expected layout from the repo manifests (mounted at
# /repo-manifests) plus the .so files baked into the image, then start the
# server. The proper fix is in Dockerfile.demo (ship the bundles directly);
# tracked in https://github.com/streamer45/streamkit/issues/553 — remove this
# shim once the demo image ships plugin bundles.
# We pass through any directory bundles the image already ships (newer images,
# see https://github.com/streamer45/streamkit/issues/553) and assemble the rest
# from the repo manifests (mounted at /repo-manifests) plus the bare .so files
# baked into the image, then start the server. Remove this shim once the pinned
# image ships plugin bundles.
set -e

SRC=/opt/streamkit/plugins/native
DST=/opt/streamkit/np/native
mkdir -p "$DST"
Comment on lines 18 to 19
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 Entrypoint.sh permission assumption for /opt/streamkit/np

The entrypoint.sh (samples/observability/skit/entrypoint.sh:18-19) creates /opt/streamkit/np/native via mkdir -p. The demo image's Dockerfile sets USER app and /opt/streamkit is owned by root (created by WORKDIR). This pre-existing issue works because the observability docker-compose mounts the entrypoint script and the container may have writable layers, but it could fail on read-only root filesystems or stricter runtime policies. This is not introduced by this PR (the mkdir -p "$DST" existed before), but the reviewer should be aware the new first-pass loop (cp -r) inherits this assumption.

Open in Devin Review (Staging)

Was this helpful? React with 👍 or 👎 to provide feedback.

Debug

Playground


for dir in "$SRC"/*/; do
[ -d "$dir" ] || continue
id=$(basename "$dir")
if [ -f "$dir/plugin.yml" ] && ls "$dir"/*.so > /dev/null 2>&1; then
cp -r "$SRC/$id" "$DST/$id"
echo "copied plugin bundle: $id"
fi
done

for manifest in /repo-manifests/*/plugin.yml; do
[ -f "$manifest" ] || continue
id=$(basename "$(dirname "$manifest")")
[ -d "$DST/$id" ] && continue
Comment on lines +21 to +33
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: entrypoint.sh correctly handles both old and new plugin layouts without conflict

The updated entrypoint.sh first copies any directory bundles from $SRC (lines 21-28), then falls back to assembling bundles from repo manifests for any remaining bare .so files (lines 30-41). The [ -d "$DST/$id" ] && continue guard at line 33 prevents the second loop from overwriting bundles already copied by the first loop. Since $DST is freshly created at line 19, there are no pre-existing directory issues. The cp -r at line 25 creates the destination directory (not copies into it) because $DST/$id doesn't exist yet at that point. For old images with only bare .so files, the first loop finds no directories with plugin.yml, so the second loop handles everything — preserving backward compatibility.

Open in Devin Review (Staging)

Was this helpful? React with 👍 or 👎 to provide feedback.

Debug

Playground

so=$(awk '/^entrypoint:/{print $2}' "$manifest" | tr -d '\r')
if [ -n "$so" ] && [ -f "$SRC/$so" ]; then
mkdir -p "$DST/$id"
Expand Down
Loading