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
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ jobs:

- name: Package all supported platforms
working-directory: plugin
run: make package
run: make package verify-package
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ jobs:

- name: Package all platforms
working-directory: plugin
run: make package
run: make package verify-package

- name: Extract checksums
working-directory: plugin
Expand Down
42 changes: 38 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
.PHONY: build test fmt vet package package-host clean
.PHONY: build test fmt vet package package-host verify-package verify-package-host clean

BIN := bin/kandev-plugin-github-status
VERSION := 0.1.1
STAGE := .build/stage
PKG_OUT := kandev-plugin-github-status-$(VERSION).tar.gz
KANDEV_BACKEND := ../kandev/apps/backend

build:
mkdir -p bin
Expand All @@ -18,18 +19,20 @@ fmt:
vet:
go vet ./server/...

## Cross-compile every platform in manifest.yaml, stage manifest + ui, pack.
## Cross-compile every platform in manifest.yaml, stage manifest + assets + ui,
## then pack the archive.
package:
rm -rf $(STAGE)
mkdir -p $(STAGE)/server
cp manifest.yaml $(STAGE)/manifest.yaml
cp -r assets $(STAGE)/assets
cp -r ui $(STAGE)/ui
GOOS=linux GOARCH=amd64 go build -o $(STAGE)/server/plugin-linux-amd64 ./server
GOOS=linux GOARCH=arm64 go build -o $(STAGE)/server/plugin-linux-arm64 ./server
GOOS=darwin GOARCH=amd64 go build -o $(STAGE)/server/plugin-darwin-amd64 ./server
GOOS=darwin GOARCH=arm64 go build -o $(STAGE)/server/plugin-darwin-arm64 ./server
GOOS=windows GOARCH=amd64 go build -o $(STAGE)/server/plugin-windows-amd64.exe ./server
go run github.com/kandev/kandev/cmd/plugin-pack -dir $(STAGE) -out $(PKG_OUT)
go -C $(KANDEV_BACKEND) run ./cmd/plugin-pack -dir $(abspath $(STAGE)) -out $(abspath $(PKG_OUT))
rm -rf $(STAGE)
@echo "Wrote $(PKG_OUT)"

Expand All @@ -38,11 +41,42 @@ package-host:
rm -rf $(STAGE)
mkdir -p $(STAGE)/server
cp manifest.yaml $(STAGE)/manifest.yaml
cp -r assets $(STAGE)/assets
cp -r ui $(STAGE)/ui
go build -o $(STAGE)/server/plugin-$$(go env GOOS)-$$(go env GOARCH)$$(go env GOEXE) ./server
go run github.com/kandev/kandev/cmd/plugin-pack -dir $(STAGE) -out $(PKG_OUT) -platform-only
go -C $(KANDEV_BACKEND) run ./cmd/plugin-pack -dir $(abspath $(STAGE)) -out $(abspath $(PKG_OUT)) -platform-only
rm -rf $(STAGE)
@echo "Wrote $(PKG_OUT)"

## Verify the generated archive, including the manifest-declared marketplace
## icon and plugin-pack's checksums, before it reaches the host installer.
define verify_package_archive
set -eu; \
VERIFY_DIR="$$(mktemp -d)"; \
Comment thread
zeval marked this conversation as resolved.
trap 'rm -rf "$$VERIFY_DIR"' EXIT; \
test -f "$(PKG_OUT)" || { echo "package not found: $(PKG_OUT)"; exit 1; }; \
tar -xzf "$(PKG_OUT)" -C "$$VERIFY_DIR"; \
test -f "$$VERIFY_DIR/manifest.yaml"; \
grep -Fx 'icon: "assets/icon.svg"' "$$VERIFY_DIR/manifest.yaml" >/dev/null; \
test -f "$$VERIFY_DIR/assets/icon.svg"; \
test -f "$$VERIFY_DIR/assets/NOTICE.md"; \
test -f "$$VERIFY_DIR/ui/bundle.js"; \
test -f "$$VERIFY_DIR/ui/plugin.css"; \
test -f "$$VERIFY_DIR/checksums.txt"; \
grep -Eq '^[0-9a-f]{64} assets/icon\.svg$$' "$$VERIFY_DIR/checksums.txt"; \
if command -v sha256sum >/dev/null 2>&1; then \
(cd "$$VERIFY_DIR" && sha256sum -c checksums.txt); \
else \
(cd "$$VERIFY_DIR" && shasum -a 256 -c checksums.txt); \
fi; \
$(1)
endef

verify-package:
@$(call verify_package_archive,for executable in server/plugin-linux-amd64 server/plugin-linux-arm64 server/plugin-darwin-amd64 server/plugin-darwin-arm64 server/plugin-windows-amd64.exe; do test -f "$$VERIFY_DIR/$$executable" || { echo "package missing $$executable"; exit 1; }; done)

verify-package-host:
@$(call verify_package_archive,test -f "$$VERIFY_DIR/server/plugin-$$(go env GOOS)-$$(go env GOARCH)$$(go env GOEXE)" || { echo "package missing host executable"; exit 1; })

clean:
rm -rf bin $(STAGE) kandev-plugin-github-status-*.tar.gz
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,15 +203,15 @@ Built against a sibling checkout of the kandev monorepo — `go.mod` has
expects `../kandev` next to it.

```bash
go test ./server/... # 59 test functions, 79 runs incl. subtests
go test ./server/... # 60 test functions, 80 runs incl. subtests
go vet ./server/...
gofmt -l .
make package-host # host platform only, fast local loop
make package # all five platforms in manifest.yaml
make package-host verify-package-host # host platform only, fast local loop
make package verify-package # all five manifest platforms
```

CI (`.github/workflows/ci.yml`) runs tidy + gofmt + vet + test on every PR,
and `build.yml` packages all five platforms. Both check out `kdlbs/kandev`
and `build.yml` packages and verifies all five platforms. Both check out `kdlbs/kandev`
as a sibling so the `replace` in `go.mod` resolves. `release.yml` is manual
(`workflow_dispatch` with a patch/minor/major bump, or a `v*` tag push): it
syncs `manifest.yaml`/`Makefile`/README, writes `CHANGELOG.md`, tags, then
Expand Down
10 changes: 10 additions & 0 deletions assets/NOTICE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Marketplace icon notice

`icon.svg` is an original Kandev integration asset. Its generic service-health
pulse motif does not reproduce or incorporate GitHub, Invertocat, or Octocat
logo artwork.

GITHUB, the GITHUB logo design, INVERTOCAT, OCTOCAT, and the OCTOCAT logo design
are trademarks of GitHub, Inc., registered in the United States and other
countries. This plugin is not affiliated with, sponsored by, or endorsed by
GitHub.
5 changes: 5 additions & 0 deletions assets/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ description: "Is it me or is it GitHub? A quiet status-bar chip that turns loud
author: "kandev"
categories: ["tools"]
repo_url: "https://github.com/kdlbs/kandev-plugin-github-status"
icon: "assets/icon.svg"

runtime:
type: binary
Expand Down
60 changes: 60 additions & 0 deletions server/manifest_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package main

import (
"encoding/xml"
"os"
"path/filepath"
"strings"
"testing"
)

func TestManifestIncludesPackagedMarketplaceIcon(t *testing.T) {
contents, err := os.ReadFile("../manifest.yaml")
if err != nil {
t.Fatal(err)
}

iconPath := manifestIconPath(string(contents))
if iconPath != "assets/icon.svg" {
t.Fatalf("manifest icon = %q, want %q", iconPath, "assets/icon.svg")
}

icon, err := os.ReadFile(filepath.Join("..", filepath.FromSlash(iconPath)))
if err != nil {
t.Fatal(err)
}
assertMarketplaceSVG(t, icon)
}

func manifestIconPath(manifest string) string {
for _, line := range strings.Split(manifest, "\n") {
if strings.HasPrefix(line, "icon:") {
return strings.Trim(strings.TrimSpace(strings.TrimPrefix(line, "icon:")), `"`)
}
}
return ""
}

func assertMarketplaceSVG(t *testing.T, icon []byte) {
t.Helper()

var root struct {
XMLName xml.Name
Width string `xml:"width,attr"`
Height string `xml:"height,attr"`
ViewBox string `xml:"viewBox,attr"`
}
if err := xml.Unmarshal(icon, &root); err != nil {
t.Fatal(err)
}
if root.XMLName.Local != "svg" || root.Width != "128" || root.Height != "128" || root.ViewBox != "0 0 128 128" {
t.Fatalf("unexpected SVG root: name=%q width=%q height=%q viewBox=%q", root.XMLName.Local, root.Width, root.Height, root.ViewBox)
}

lower := strings.ToLower(string(icon))
for _, forbidden := range []string{"<script", "<foreignobject", "href=", "url(", "currentcolor"} {
if strings.Contains(lower, forbidden) {
t.Fatalf("marketplace SVG contains forbidden content %q", forbidden)
}
}
}
Loading