WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
package sandbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/moby/moby/api/types/image"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDockerCreateSnapshotTagsASkillImage(t *testing.T) {
|
||||
engine := newFakeDockerEngine()
|
||||
docker := newTestDockerClient(t, engine)
|
||||
|
||||
ref, err := docker.CreateSnapshot(context.Background(), "container-1", "weknora-sk-cfg1-g1")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "weknora-skill/weknora-sk-cfg1-g1", ref.ID)
|
||||
require.Len(t, engine.committed, 1)
|
||||
require.Equal(t, "weknora-skill/weknora-sk-cfg1-g1", engine.committed[0].Reference)
|
||||
require.False(t, engine.committed[0].NoPause,
|
||||
"the Engine must pause the container for the duration of the commit")
|
||||
require.Contains(t, engine.committed[0].Changes, "LABEL "+dockerSkillSnapshotLabel+"=true")
|
||||
require.Contains(t, engine.committed[0].Changes,
|
||||
"LABEL "+dockerSkillSnapshotSourceLabel+"=container-1")
|
||||
}
|
||||
|
||||
func TestDockerCreateSnapshotRejectsEmptySandboxID(t *testing.T) {
|
||||
_, err := newTestDockerClient(t, newFakeDockerEngine()).
|
||||
CreateSnapshot(context.Background(), " ", "n")
|
||||
require.True(t, IsRemoteInvalidRequest(err))
|
||||
}
|
||||
|
||||
func TestDockerDeleteSnapshotTreatsMissingAsSuccess(t *testing.T) {
|
||||
err := newTestDockerClient(t, newFakeDockerEngine()).
|
||||
DeleteSnapshot(context.Background(), "weknora-skill/missing")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestDockerDeleteSnapshotRejectsEmptySnapshotID(t *testing.T) {
|
||||
err := newTestDockerClient(t, newFakeDockerEngine()).
|
||||
DeleteSnapshot(context.Background(), " ")
|
||||
require.True(t, IsRemoteInvalidRequest(err))
|
||||
}
|
||||
|
||||
func TestDockerSnapshotRoundTripAndListFilter(t *testing.T) {
|
||||
engine := newFakeDockerEngine()
|
||||
docker := newTestDockerClient(t, engine)
|
||||
ctx := context.Background()
|
||||
|
||||
first, err := docker.CreateSnapshot(ctx, "container-a", "weknora-sk-a-g1")
|
||||
require.NoError(t, err)
|
||||
second, err := docker.CreateSnapshot(ctx, "container-a", "weknora-sk-a-g2")
|
||||
require.NoError(t, err)
|
||||
_, err = docker.CreateSnapshot(ctx, "container-b", "weknora-sk-b-g1")
|
||||
require.NoError(t, err)
|
||||
|
||||
all, err := docker.ListSnapshots(ctx, "")
|
||||
require.NoError(t, err)
|
||||
require.Len(t, all, 3)
|
||||
|
||||
fromA, err := docker.ListSnapshots(ctx, "container-a")
|
||||
require.NoError(t, err)
|
||||
require.Len(t, fromA, 2)
|
||||
ids := map[string]struct{}{fromA[0].ID: {}, fromA[1].ID: {}}
|
||||
require.Contains(t, ids, first.ID)
|
||||
require.Contains(t, ids, second.ID)
|
||||
|
||||
require.NoError(t, docker.DeleteSnapshot(ctx, first.ID))
|
||||
require.NoError(t, docker.DeleteSnapshot(ctx, first.ID), "deleting twice must stay idempotent")
|
||||
|
||||
fromA, err = docker.ListSnapshots(ctx, "container-a")
|
||||
require.NoError(t, err)
|
||||
require.Len(t, fromA, 1)
|
||||
require.Equal(t, second.ID, fromA[0].ID)
|
||||
}
|
||||
|
||||
// Each generation is committed from a container started off the previous one,
|
||||
// so untagging one alone frees nothing while its descendant lives. Without
|
||||
// noprune=0 the layers of a fully retired chain would stay on disk forever.
|
||||
func TestDockerDeleteSnapshotPrunesUntaggedAncestors(t *testing.T) {
|
||||
engine := newFakeDockerEngine()
|
||||
docker := newTestDockerClient(t, engine)
|
||||
|
||||
ref, err := docker.CreateSnapshot(context.Background(), "container-a", "weknora-sk-a-g1")
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, docker.DeleteSnapshot(context.Background(), ref.ID))
|
||||
|
||||
require.True(t, engine.removeImageOptions[0].PruneChildren,
|
||||
"a delete that keeps untagged parents can never reclaim a retired chain")
|
||||
require.False(t, engine.removeImageOptions[0].Force,
|
||||
"force-remove would untag an image a live session container still holds")
|
||||
}
|
||||
|
||||
// A skill snapshot the ledger cannot name is unreachable: snapshots are always
|
||||
// addressed by the tag CreateSnapshot mints, never by digest.
|
||||
func TestDockerDeleteSnapshotSweepsUntaggedSkillImages(t *testing.T) {
|
||||
engine := newFakeDockerEngine()
|
||||
engine.images = []image.Summary{
|
||||
{
|
||||
ID: "sha256:retired",
|
||||
RepoTags: []string{"weknora-skill/weknora-sk-a-g1:latest"},
|
||||
Labels: map[string]string{dockerSkillSnapshotLabel: "true"},
|
||||
},
|
||||
{
|
||||
ID: "sha256:orphan",
|
||||
RepoTags: []string{"<none>:<none>"},
|
||||
Labels: map[string]string{dockerSkillSnapshotLabel: "true"},
|
||||
},
|
||||
{
|
||||
ID: "sha256:live",
|
||||
RepoTags: []string{"weknora-skill/weknora-sk-a-g2:latest"},
|
||||
Labels: map[string]string{dockerSkillSnapshotLabel: "true"},
|
||||
},
|
||||
{
|
||||
ID: "sha256:base",
|
||||
RepoTags: []string{"weknora/sandbox:test"},
|
||||
Labels: map[string]string{dockerTemplateLabel: "true"},
|
||||
},
|
||||
}
|
||||
docker := newTestDockerClient(t, engine)
|
||||
|
||||
require.NoError(t, docker.DeleteSnapshot(
|
||||
context.Background(), "weknora-skill/weknora-sk-a-g1"))
|
||||
|
||||
require.Equal(t,
|
||||
[]string{"weknora-skill/weknora-sk-a-g1", "sha256:orphan"},
|
||||
engine.removedImages,
|
||||
"the sweep must take the untagged snapshot and nothing that is still named")
|
||||
}
|
||||
|
||||
func TestDockerDeleteSnapshotSweepFailureIsNotAnError(t *testing.T) {
|
||||
engine := newFakeDockerEngine()
|
||||
engine.images = []image.Summary{
|
||||
{
|
||||
ID: "sha256:orphan",
|
||||
RepoTags: []string{"<none>:<none>"},
|
||||
Labels: map[string]string{dockerSkillSnapshotLabel: "true"},
|
||||
},
|
||||
}
|
||||
engine.imagePresent["weknora-skill/weknora-sk-a-g1"] = true
|
||||
engine.listImagesErr = errors.New("daemon busy")
|
||||
docker := newTestDockerClient(t, engine)
|
||||
|
||||
require.NoError(t, docker.DeleteSnapshot(
|
||||
context.Background(), "weknora-skill/weknora-sk-a-g1"),
|
||||
"reclaiming storage must not turn a completed delete into a failure")
|
||||
}
|
||||
|
||||
func TestDockerListTemplatesHidesSkillSnapshots(t *testing.T) {
|
||||
engine := newFakeDockerEngine()
|
||||
engine.images = []image.Summary{
|
||||
{
|
||||
ID: "sha256:base",
|
||||
RepoTags: []string{"weknora/sandbox:test"},
|
||||
Labels: map[string]string{dockerTemplateLabel: "true"},
|
||||
},
|
||||
{
|
||||
ID: "sha256:snap",
|
||||
RepoTags: []string{"weknora-skill/weknora-sk-cfg1-g1:latest"},
|
||||
Labels: map[string]string{dockerSkillSnapshotLabel: "true"},
|
||||
},
|
||||
}
|
||||
docker := newTestDockerClient(t, engine)
|
||||
|
||||
templates, err := docker.ListTemplates(context.Background())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, templates, 1)
|
||||
require.Equal(t, "weknora/sandbox:test", templates[0].ID)
|
||||
}
|
||||
|
||||
func TestDockerCreateDoesNotPullAMissingSkillSnapshot(t *testing.T) {
|
||||
engine := newFakeDockerEngine()
|
||||
docker := newTestDockerClient(t, engine)
|
||||
|
||||
_, err := docker.Create(context.Background(), RemoteCreateRequest{
|
||||
TemplateID: "weknora-skill/weknora-sk-cfg1-g1",
|
||||
})
|
||||
require.True(t, IsRemoteInvalidRequest(err), err)
|
||||
require.Empty(t, engine.pulled,
|
||||
"a local commit must not be fetched from a registry")
|
||||
}
|
||||
|
||||
func TestDockerSanitizeImageName(t *testing.T) {
|
||||
require.Equal(t, "weknora-sk-cfg1-g1", dockerSanitizeImageName("weknora-sk-cfg1-g1"))
|
||||
require.Equal(t, "abc-def", dockerSanitizeImageName("ABC_DEF"))
|
||||
require.Equal(t, "snap", dockerSanitizeImageName("--snap--"))
|
||||
require.Empty(t, dockerSanitizeImageName("***"))
|
||||
}
|
||||
Reference in New Issue
Block a user