Compare commits
3 Commits
f074d71cf9
...
4eb4bcfc50
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4eb4bcfc50 | ||
|
|
7cfc371a42 | ||
|
|
1fb8a634ab |
@ -1107,12 +1107,29 @@ func writeMod(path string, m *core.ModFile) error {
|
|||||||
}
|
}
|
||||||
fmt.Fprintf(&b, "tags = [%s]\n", strings.Join(quoted, ", "))
|
fmt.Fprintf(&b, "tags = [%s]\n", strings.Join(quoted, ", "))
|
||||||
}
|
}
|
||||||
|
if len(m.Plugin.RequiredIconPacks) > 0 {
|
||||||
|
quoted := make([]string, len(m.Plugin.RequiredIconPacks))
|
||||||
|
for i, p := range m.Plugin.RequiredIconPacks {
|
||||||
|
quoted[i] = fmt.Sprintf("%q", p)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&b, "required_icon_packs = [%s]\n", strings.Join(quoted, ", "))
|
||||||
|
}
|
||||||
if m.Plugin.Private {
|
if m.Plugin.Private {
|
||||||
b.WriteString("private = true\n")
|
b.WriteString("private = true\n")
|
||||||
}
|
}
|
||||||
if m.Plugin.DataDir {
|
if m.Plugin.DataDir {
|
||||||
b.WriteString("data_dir = true\n")
|
b.WriteString("data_dir = true\n")
|
||||||
}
|
}
|
||||||
|
if len(m.Plugin.AllowedHosts) > 0 {
|
||||||
|
quoted := make([]string, len(m.Plugin.AllowedHosts))
|
||||||
|
for i, h := range m.Plugin.AllowedHosts {
|
||||||
|
quoted[i] = fmt.Sprintf("%q", h)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&b, "allowed_hosts = [%s]\n", strings.Join(quoted, ", "))
|
||||||
|
}
|
||||||
|
if m.Plugin.MaxResponseMB > 0 {
|
||||||
|
fmt.Fprintf(&b, "max_response_mb = %d\n", m.Plugin.MaxResponseMB)
|
||||||
|
}
|
||||||
if m.Compatibility != nil {
|
if m.Compatibility != nil {
|
||||||
b.WriteString("\n[compatibility]\n")
|
b.WriteString("\n[compatibility]\n")
|
||||||
fmt.Fprintf(&b, "block_core = %q\n", m.Compatibility.BlockCore)
|
fmt.Fprintf(&b, "block_core = %q\n", m.Compatibility.BlockCore)
|
||||||
|
|||||||
@ -364,6 +364,45 @@ func TestWriteMod_PrivateFalseOmitted(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestWriteMod_RoundTripsFirstClassFields guards the writeMod ⇄ ParseModFull
|
||||||
|
// round-trip for the first-class fields the hand-rolled writer must emit: a
|
||||||
|
// bump/init/tags edit re-serializes plugin.mod, and any field the writer forgets
|
||||||
|
// is silently dropped. allowed_hosts (ADR 0023) dropping is a security-relevant
|
||||||
|
// regression — a bump strips the egress declaration and the consent gate goes
|
||||||
|
// dark — so this test exists to keep the writer in sync with core.ModFile.
|
||||||
|
func TestWriteMod_RoundTripsFirstClassFields(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
path := filepath.Join(dir, "plugin.mod")
|
||||||
|
m := &core.ModFile{Plugin: core.ModPlugin{
|
||||||
|
Name: "myplugin",
|
||||||
|
Scope: "ninja",
|
||||||
|
Version: "1.2.3",
|
||||||
|
AllowedHosts: []string{"api.cal.com", "*.example.com"},
|
||||||
|
MaxResponseMB: 25,
|
||||||
|
RequiredIconPacks: []string{"tabler"},
|
||||||
|
}}
|
||||||
|
if err := writeMod(path, m); err != nil {
|
||||||
|
t.Fatalf("writeMod: %v", err)
|
||||||
|
}
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read back: %v", err)
|
||||||
|
}
|
||||||
|
back, err := core.ParseModFull(data)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ParseModFull round-trip: %v\n%s", err, data)
|
||||||
|
}
|
||||||
|
if got := back.Plugin.AllowedHosts; len(got) != 2 || got[0] != "api.cal.com" || got[1] != "*.example.com" {
|
||||||
|
t.Errorf("allowed_hosts not preserved: %v\n%s", got, data)
|
||||||
|
}
|
||||||
|
if back.Plugin.MaxResponseMB != 25 {
|
||||||
|
t.Errorf("max_response_mb not preserved: %d\n%s", back.Plugin.MaxResponseMB, data)
|
||||||
|
}
|
||||||
|
if got := back.Plugin.RequiredIconPacks; len(got) != 1 || got[0] != "tabler" {
|
||||||
|
t.Errorf("required_icon_packs not preserved: %v\n%s", got, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestParsePrivateCoord(t *testing.T) {
|
func TestParsePrivateCoord(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
in string
|
in string
|
||||||
|
|||||||
7
go.mod
7
go.mod
@ -5,7 +5,7 @@ go 1.26.4
|
|||||||
require (
|
require (
|
||||||
connectrpc.com/connect v1.20.0
|
connectrpc.com/connect v1.20.0
|
||||||
git.dev.alexdunmow.com/block/core v0.18.2
|
git.dev.alexdunmow.com/block/core v0.18.2
|
||||||
git.dev.alexdunmow.com/block/pluginsdk v0.1.0
|
git.dev.alexdunmow.com/block/pluginsdk v0.2.5
|
||||||
github.com/chromedp/cdproto v0.0.0-20260321001828-e3e3800016bc
|
github.com/chromedp/cdproto v0.0.0-20260321001828-e3e3800016bc
|
||||||
github.com/chromedp/chromedp v0.15.1
|
github.com/chromedp/chromedp v0.15.1
|
||||||
github.com/klauspost/compress v1.18.6
|
github.com/klauspost/compress v1.18.6
|
||||||
@ -30,6 +30,7 @@ require (
|
|||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.9 // indirect
|
github.com/spf13/pflag v1.0.9 // indirect
|
||||||
golang.org/x/mod v0.37.0 // indirect
|
golang.org/x/mod v0.37.0 // indirect
|
||||||
golang.org/x/sys v0.44.0 // indirect
|
golang.org/x/net v0.56.0 // indirect
|
||||||
golang.org/x/text v0.36.0 // indirect
|
golang.org/x/sys v0.46.0 // indirect
|
||||||
|
golang.org/x/text v0.38.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
18
go.sum
18
go.sum
@ -2,8 +2,8 @@ connectrpc.com/connect v1.20.0 h1:6TNDAB+WeNd2uolWNlYczB5E0KNNaVMNUEx8JEUsPmQ=
|
|||||||
connectrpc.com/connect v1.20.0/go.mod h1:A2ygJrukXwWy32vkCAAHNVguZrqZ+jeZ9rGRnGR4dN4=
|
connectrpc.com/connect v1.20.0/go.mod h1:A2ygJrukXwWy32vkCAAHNVguZrqZ+jeZ9rGRnGR4dN4=
|
||||||
git.dev.alexdunmow.com/block/core v0.18.2 h1:+3OfZ424yoc1k1CucXYARk8TBkh8Z693HRkhf5Ci2wU=
|
git.dev.alexdunmow.com/block/core v0.18.2 h1:+3OfZ424yoc1k1CucXYARk8TBkh8Z693HRkhf5Ci2wU=
|
||||||
git.dev.alexdunmow.com/block/core v0.18.2/go.mod h1:GGuUu826AoJepC/hKLGJ7BX3PQaDss9ueCT0se6Ao2w=
|
git.dev.alexdunmow.com/block/core v0.18.2/go.mod h1:GGuUu826AoJepC/hKLGJ7BX3PQaDss9ueCT0se6Ao2w=
|
||||||
git.dev.alexdunmow.com/block/pluginsdk v0.1.0 h1:Dgbt8Q5b+1o3HdftQ7yhV2byWI5q3exiN9oXhwz2MjM=
|
git.dev.alexdunmow.com/block/pluginsdk v0.2.5 h1:01d+5stAywSENScafnNKyMc2ZM5GGFt+hCBKuKTFJW4=
|
||||||
git.dev.alexdunmow.com/block/pluginsdk v0.1.0/go.mod h1:uz6oRurbuHdTcUxg47ymVgBqRARKlpXp1JIziXevzms=
|
git.dev.alexdunmow.com/block/pluginsdk v0.2.5/go.mod h1:Z+eG+WZxAP0jfreLqlGcc0kkWKt8RWevzWyWn8d+dhM=
|
||||||
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
|
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
|
||||||
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
github.com/chromedp/cdproto v0.0.0-20260321001828-e3e3800016bc h1:wkN/LMi5vc60pBRWx6qpbk/aEvq3/ZVNpnMvsw8PVVU=
|
github.com/chromedp/cdproto v0.0.0-20260321001828-e3e3800016bc h1:wkN/LMi5vc60pBRWx6qpbk/aEvq3/ZVNpnMvsw8PVVU=
|
||||||
@ -68,13 +68,15 @@ github.com/tetratelabs/wazero v1.12.0/go.mod h1:LvKtzl2RqO4gyF27BiXU+nKAjcV8f38U
|
|||||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||||
golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
|
golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
|
||||||
golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
|
golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
|
||||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
|
||||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
|
||||||
|
golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
|
||||||
|
golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
|
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
|
||||||
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
|
golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
|
||||||
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
|
golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import (
|
|||||||
|
|
||||||
abiv1 "git.dev.alexdunmow.com/block/pluginsdk/abi/v1"
|
abiv1 "git.dev.alexdunmow.com/block/pluginsdk/abi/v1"
|
||||||
core "git.dev.alexdunmow.com/block/pluginsdk/plugin"
|
core "git.dev.alexdunmow.com/block/pluginsdk/plugin"
|
||||||
|
"git.dev.alexdunmow.com/block/pluginsdk/egress"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -128,6 +129,16 @@ func Build(ctx context.Context, opts BuildOptions) (*BuildResult, error) {
|
|||||||
// grant crosses from mod → manifest; the loader then reads one source.
|
// grant crosses from mod → manifest; the loader then reads one source.
|
||||||
manifest.DataDir = mod.Plugin.DataDir
|
manifest.DataDir = mod.Plugin.DataDir
|
||||||
|
|
||||||
|
// 4a. Stamp the egress declaration (ADR 0023). Validate the host-pattern
|
||||||
|
// grammar here so a malformed allowed_hosts fails the build, not the
|
||||||
|
// install; the platform denylist is enforced host-side at publish and
|
||||||
|
// fetch (it needs the instance's own domains, which the packer lacks).
|
||||||
|
if _, err := egress.ParseAllowlist(mod.Plugin.AllowedHosts); err != nil {
|
||||||
|
return nil, fmt.Errorf("allowed_hosts: %w", err)
|
||||||
|
}
|
||||||
|
manifest.AllowedHosts = mod.Plugin.AllowedHosts
|
||||||
|
manifest.MaxResponseMb = mod.Plugin.MaxResponseMB
|
||||||
|
|
||||||
// 4b. Mixed-form artifacts (WO-WZ-021): a reduced wasm plugin may keep a
|
// 4b. Mixed-form artifacts (WO-WZ-021): a reduced wasm plugin may keep a
|
||||||
// minimal guest for genuine logic (a contact route, Stripe) while its
|
// minimal guest for genuine logic (a contact route, Stripe) while its
|
||||||
// declarative surfaces (theme presets, bundled fonts, master pages,
|
// declarative surfaces (theme presets, bundled fonts, master pages,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user