Compare commits
10 Commits
6ae0267df2
...
9a9519186b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a9519186b | ||
|
|
5675dbb2eb | ||
|
|
ab29b81133 | ||
|
|
19d09ffb32 | ||
|
|
8143336564 | ||
|
|
2979dc9b26 | ||
|
|
ab76ef531d | ||
|
|
2e390edb12 | ||
|
|
d145a5b689 | ||
|
|
a0558bc6a0 |
19
.github/workflows/push.yml
vendored
19
.github/workflows/push.yml
vendored
@@ -7,8 +7,14 @@ on:
|
||||
jobs:
|
||||
|
||||
build:
|
||||
name: build-and-test
|
||||
runs-on: ubuntu-latest
|
||||
name: CI
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- macos-latest
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
@@ -21,14 +27,19 @@ jobs:
|
||||
id: go
|
||||
|
||||
- name: Ensure all files were formatted as per gofmt
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
[ "$(gofmt -l $(find . -name '*.go') 2>&1)" = "" ]
|
||||
|
||||
- name: Build and run tests
|
||||
- name: Build
|
||||
run: |
|
||||
go install -mod=mod ./cmd/...
|
||||
|
||||
- name: Run tests
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
# TestRelativeParentDir verifies breakglass.authorized_keys
|
||||
# is correctly included, and the gok CLI only creates that
|
||||
# file when it finds SSH keys.
|
||||
run: |
|
||||
mkdir -p ~/.ssh && echo dummy > ~/.ssh/id_ed25519.pub
|
||||
go install -mod=mod ./cmd/...
|
||||
go test -mod=mod -v ./...
|
||||
|
||||
22
go.mod
22
go.mod
@@ -1,24 +1,26 @@
|
||||
module github.com/gokrazy/tools
|
||||
|
||||
go 1.24
|
||||
go 1.24.0
|
||||
|
||||
toolchain go1.24.6
|
||||
|
||||
require (
|
||||
github.com/breml/rootcerts v0.2.20
|
||||
github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0
|
||||
github.com/gokrazy/gokapi v0.0.0-20250222080418-e140e9c461d8
|
||||
github.com/gokrazy/internal v0.0.0-20250520205945-c2e4e2b4f611
|
||||
github.com/gokrazy/updater v0.0.0-20230215172637-813ccc7f21e2
|
||||
github.com/gokrazy/internal v0.0.0-20250526201501-559979153369
|
||||
github.com/gokrazy/updater v0.0.0-20250705135802-db129c40879c
|
||||
github.com/google/renameio/v2 v2.0.0
|
||||
github.com/mattn/go-isatty v0.0.20
|
||||
github.com/spf13/cobra v1.6.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
golang.org/x/mod v0.23.0
|
||||
golang.org/x/sync v0.1.0
|
||||
golang.org/x/sys v0.28.0
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/spf13/pflag v1.0.6
|
||||
golang.org/x/crypto/x509roots/fallback v0.0.0-20250911151450-96dc232fbd79
|
||||
golang.org/x/mod v0.24.0
|
||||
golang.org/x/sync v0.14.0
|
||||
golang.org/x/sys v0.33.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/antihax/optional v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
golang.org/x/oauth2 v0.23.0 // indirect
|
||||
golang.org/x/oauth2 v0.27.0 // indirect
|
||||
)
|
||||
|
||||
39
go.sum
39
go.sum
@@ -1,38 +1,37 @@
|
||||
github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/breml/rootcerts v0.2.20 h1:koth1lShwiiDp3VOX6/4qKEZ87S7HgDKsnDr47XEIq0=
|
||||
github.com/breml/rootcerts v0.2.20/go.mod h1:S/PKh+4d1HUn4HQovEB8hPJZO6pUZYrIhmXBhsegfXw=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 h1:C7t6eeMaEQVy6e8CarIhscYQlNmw5e3G36y7l7Y21Ao=
|
||||
github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0/go.mod h1:56wL82FO0bfMU5RvfXoIwSOP2ggqqxT+tAfNEIyxuHw=
|
||||
github.com/gokrazy/gokapi v0.0.0-20250222080418-e140e9c461d8 h1:BvyzTtbpz1GCGD35Z3G/ZR0nK0j3Fh+dRCCso+w3RKE=
|
||||
github.com/gokrazy/gokapi v0.0.0-20250222080418-e140e9c461d8/go.mod h1:rVItujrJo0NpYZhFR5dYdzLDqMoMCtjEZkdxoCRDo+o=
|
||||
github.com/gokrazy/internal v0.0.0-20250520205945-c2e4e2b4f611 h1:BcmhkIKeIsw5xGheRGOCj97zjevG+VImWiP2/XGF2Gg=
|
||||
github.com/gokrazy/internal v0.0.0-20250520205945-c2e4e2b4f611/go.mod h1:dQY4EMkD4L5ZjYJ0SPtpgYbV7MIUMCxNIXiOfnZ6jP4=
|
||||
github.com/gokrazy/updater v0.0.0-20230215172637-813ccc7f21e2 h1:kBY5R1tSf+EYZ+QaSrofLaVJtBqYsVNVBWkdMq3Smcg=
|
||||
github.com/gokrazy/updater v0.0.0-20230215172637-813ccc7f21e2/go.mod h1:PYOvzGOL4nlBmuxu7IyKQTFLaxr61+WPRNRzVtuYOHw=
|
||||
github.com/gokrazy/internal v0.0.0-20250526201501-559979153369 h1:aNni2iPwJbowfHW1SFapKLfY+ZPUIcBfFrJvYPAh3p4=
|
||||
github.com/gokrazy/internal v0.0.0-20250526201501-559979153369/go.mod h1:dQY4EMkD4L5ZjYJ0SPtpgYbV7MIUMCxNIXiOfnZ6jP4=
|
||||
github.com/gokrazy/updater v0.0.0-20250705135802-db129c40879c h1:j4/v9FR/cOy6nog5rmXUtauBsOU3mm+rTPn5IENUbmg=
|
||||
github.com/gokrazy/updater v0.0.0-20250705135802-db129c40879c/go.mod h1:EtAn+BPibqnAHnYGj3FW5e284xNsiOOMOL2dJiwu7H4=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
|
||||
github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
|
||||
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
|
||||
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
|
||||
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
|
||||
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
golang.org/x/crypto/x509roots/fallback v0.0.0-20250911151450-96dc232fbd79 h1:WZWglxfb13JCTbJyKY1pk0V94spHxJzMAQW29INytRQ=
|
||||
golang.org/x/crypto/x509roots/fallback v0.0.0-20250911151450-96dc232fbd79/go.mod h1:MEIPiCnxvQEjA4astfaKItNwEVZA5Ki+3+nyGbJ5N18=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
|
||||
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
197
integration/gokupdate/gokupdate_test.go
Normal file
197
integration/gokupdate/gokupdate_test.go
Normal file
@@ -0,0 +1,197 @@
|
||||
package gokupdate_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"hash"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gokrazy/internal/config"
|
||||
"github.com/gokrazy/tools/gok"
|
||||
"github.com/gokrazy/tools/internal/packer"
|
||||
)
|
||||
|
||||
type gokrazyTestInstance struct {
|
||||
configDir string
|
||||
}
|
||||
|
||||
func (inst *gokrazyTestInstance) writeConfig(t *testing.T, basename, content string) {
|
||||
t.Helper()
|
||||
fn := filepath.Join(inst.configDir, basename)
|
||||
if err := os.WriteFile(fn, []byte(content), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeGokrazyInstance(t *testing.T) *gokrazyTestInstance {
|
||||
t.Helper()
|
||||
|
||||
// Redirect os.UserConfigDir() to a temporary directory under our
|
||||
// control. gokrazy always uses a path under os.UserConfigDir().
|
||||
var configDir string
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
configHomeDir := t.TempDir()
|
||||
os.Setenv("XDG_CONFIG_HOME", configHomeDir)
|
||||
// where linux looks:
|
||||
configDir = filepath.Join(configHomeDir, "gokrazy")
|
||||
|
||||
case "darwin":
|
||||
homeDir := t.TempDir()
|
||||
os.Setenv("HOME", homeDir)
|
||||
// where darwin looks:
|
||||
configDir = filepath.Join(homeDir, "Library", "Application Support", "gokrazy")
|
||||
|
||||
default:
|
||||
t.Fatalf("GOOS=%s unsupported", runtime.GOOS)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(configDir, 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return &gokrazyTestInstance{
|
||||
configDir: configDir,
|
||||
}
|
||||
}
|
||||
|
||||
func TestGokUpdate(t *testing.T) {
|
||||
// Run this whole test in a throw-away temporary directory to not litter the
|
||||
// gokrazy/tools repository working copy.
|
||||
t.Chdir(t.TempDir())
|
||||
|
||||
_ = writeGokrazyInstance(t)
|
||||
|
||||
// TODO: run the gokrazy instance in a VM instead of providing a fake
|
||||
// implementation of the update protocol.
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/update/features", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "not found", http.StatusNotFound)
|
||||
})
|
||||
mux.HandleFunc("/update/", func(w http.ResponseWriter, r *http.Request) {
|
||||
// accept whatever for now.
|
||||
var hash hash.Hash
|
||||
switch r.Header.Get("X-Gokrazy-Update-Hash") {
|
||||
case "crc32":
|
||||
hash = crc32.NewIEEE()
|
||||
default:
|
||||
hash = sha256.New()
|
||||
}
|
||||
if _, err := io.Copy(hash, r.Body); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(w, "%x", hash.Sum(nil))
|
||||
})
|
||||
mux.HandleFunc("/reboot", func(w http.ResponseWriter, r *http.Request) {
|
||||
// you got it, boss!
|
||||
})
|
||||
mux.HandleFunc("/uploadtemp/", func(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("[HTTP] uploadtemp: %s", r.URL.Path)
|
||||
})
|
||||
mux.HandleFunc("/divert", func(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("[HTTP] divert: %s to %s",
|
||||
r.FormValue("path"),
|
||||
r.FormValue("diversion"))
|
||||
})
|
||||
mux.HandleFunc("/log", func(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("[HTTP] log: %s", r.FormValue("path"))
|
||||
w.Header().Set("Content-type", "text/event-stream")
|
||||
if r.FormValue("stream") == "stdout" {
|
||||
const text = "Hello Sun"
|
||||
line := fmt.Sprintf("data: %s\n", text)
|
||||
if _, err := fmt.Fprintln(w, line); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if f, ok := w.(http.Flusher); ok {
|
||||
f.Flush()
|
||||
}
|
||||
select {}
|
||||
})
|
||||
fakeBuildTimestamp := "fake-" + time.Now().Format(time.RFC3339)
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.Contains(strings.ToLower(r.Header.Get("Accept")), "application/json") {
|
||||
status := struct {
|
||||
BuildTimestamp string `json:"BuildTimestamp"`
|
||||
}{
|
||||
BuildTimestamp: fakeBuildTimestamp,
|
||||
}
|
||||
b, err := json.Marshal(&status)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(b)
|
||||
return
|
||||
}
|
||||
http.Error(w, "handler not implemented", http.StatusNotImplemented)
|
||||
})
|
||||
srv := httptest.NewServer(mux)
|
||||
u, err := url.Parse(srv.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// create a new instance
|
||||
c := gok.Context{
|
||||
Args: []string{
|
||||
"--parent_dir", "gokrazy",
|
||||
"-i", "hello",
|
||||
"new",
|
||||
},
|
||||
}
|
||||
t.Logf("running %q", append([]string{"<gok>"}, c.Args...))
|
||||
if err := c.Execute(context.Background()); err != nil {
|
||||
t.Fatalf("%v: %v", c.Args, err)
|
||||
}
|
||||
|
||||
// update the instance config to speak to the test server
|
||||
const configPath = "gokrazy/hello/config.json"
|
||||
b, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var cfg config.Struct
|
||||
if err := json.Unmarshal(b, &cfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cfg.Update.Hostname = "localhost"
|
||||
cfg.Update.HTTPPort = u.Port()
|
||||
t.Logf("Updated cfg.Update = %+v", cfg.Update)
|
||||
b, err = cfg.FormatForFile()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(configPath, b, 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// verify overwrite works (i.e. locates extrafiles)
|
||||
ctx := context.WithValue(context.Background(), packer.BuildTimestampOverride, fakeBuildTimestamp)
|
||||
c = gok.Context{
|
||||
Args: []string{
|
||||
"--parent_dir", "gokrazy",
|
||||
"-i", "hello",
|
||||
"update",
|
||||
},
|
||||
}
|
||||
t.Logf("running %q", append([]string{"<gok>"}, c.Args...))
|
||||
if err := c.Execute(ctx); err != nil {
|
||||
t.Fatalf("%v: %v", c.Args, err)
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,10 @@ import (
|
||||
func TestNonModuleFiles(t *testing.T) {
|
||||
// Run this whole test in a throw-away temporary directory to not litter the
|
||||
// gokrazy/tools repository working copy.
|
||||
parent := t.TempDir()
|
||||
t.Chdir(t.TempDir())
|
||||
|
||||
// create a new instance
|
||||
parent := t.TempDir()
|
||||
c := gok.Context{
|
||||
Args: []string{
|
||||
"--parent_dir=" + parent,
|
||||
|
||||
@@ -13,22 +13,7 @@ import (
|
||||
func TestRelativeParentDir(t *testing.T) {
|
||||
// Run this whole test in a throw-away temporary directory to not litter the
|
||||
// gokrazy/tools repository working copy.
|
||||
|
||||
// TODO(go1.24): use t.Chdir()
|
||||
oldwd, err := os.Open(".")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Chdir(t.TempDir()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
err := oldwd.Chdir()
|
||||
oldwd.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
t.Chdir(t.TempDir())
|
||||
|
||||
// create a new instance
|
||||
c := gok.Context{
|
||||
|
||||
@@ -151,7 +151,7 @@ func (r *overwriteImplConfig) run(ctx context.Context, args []string, stdout, st
|
||||
Output: &output,
|
||||
}
|
||||
|
||||
pack.Main("gokrazy gok")
|
||||
pack.Main(ctx, "gokrazy gok")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ func (r *runImplConfig) run(ctx context.Context, args []string, stdout, stderr i
|
||||
return err
|
||||
}
|
||||
|
||||
target, err := updater.NewTarget(updateBaseUrl.String(), httpClient)
|
||||
target, err := updater.NewTarget(ctx, updateBaseUrl.String(), httpClient)
|
||||
if err != nil {
|
||||
return fmt.Errorf("checking target partuuid support: %v", err)
|
||||
}
|
||||
@@ -153,7 +153,7 @@ func (r *runImplConfig) run(ctx context.Context, args []string, stdout, stderr i
|
||||
|
||||
{
|
||||
start := time.Now()
|
||||
err := target.Put("uploadtemp/gok-run/"+basename, io.TeeReader(f, &progress.Writer{}))
|
||||
err := target.Put(ctx, "uploadtemp/gok-run/"+basename, io.TeeReader(f, &progress.Writer{}))
|
||||
if err != nil {
|
||||
return fmt.Errorf("uploading temporary binary: %v", err)
|
||||
}
|
||||
@@ -171,6 +171,7 @@ func (r *runImplConfig) run(ctx context.Context, args []string, stdout, stderr i
|
||||
// /user/<basename>. Includes an automatic service restart.
|
||||
{
|
||||
err := target.Divert(
|
||||
ctx,
|
||||
"/user/"+basename,
|
||||
"gok-run/"+basename,
|
||||
cfg.PackageConfig[importPath].CommandLineFlags,
|
||||
|
||||
@@ -80,7 +80,7 @@ func (r *sbomConfig) run(ctx context.Context, args []string, stdout, stderr io.W
|
||||
Cfg: cfg,
|
||||
}
|
||||
|
||||
sbomMarshaled, sbomWithHash, err := pack.GenerateSBOM()
|
||||
sbomMarshaled, sbomWithHash, err := pack.GenerateSBOM(ctx)
|
||||
if os.IsNotExist(err) {
|
||||
// Common case, handle with a good error message
|
||||
os.Stderr.WriteString("\n")
|
||||
|
||||
@@ -90,7 +90,7 @@ func (r *updateImplConfig) run(ctx context.Context, args []string, stdout, stder
|
||||
Cfg: cfg,
|
||||
}
|
||||
|
||||
pack.Main("gokrazy gok")
|
||||
pack.Main(ctx, "gokrazy gok")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -76,11 +76,7 @@ func init() {
|
||||
instanceflag.RegisterPflags(vmRunCmd.Flags())
|
||||
}
|
||||
|
||||
func (r *vmRunConfig) buildFullDiskImage(ctx context.Context, dest string) error {
|
||||
fileCfg, err := config.ApplyInstanceFlag()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func (r *vmRunConfig) buildFullDiskImage(ctx context.Context, dest string, fileCfg *config.Struct) error {
|
||||
|
||||
if r.arch != "" {
|
||||
os.Setenv("GOARCH", r.arch)
|
||||
@@ -137,7 +133,7 @@ func (r *vmRunConfig) buildFullDiskImage(ctx context.Context, dest string) error
|
||||
Output: &output,
|
||||
}
|
||||
|
||||
pack.Main("gokrazy gok")
|
||||
pack.Main(ctx, "gokrazy gok")
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -231,6 +227,22 @@ func (r *vmRunConfig) runQEMU(ctx context.Context, fullDiskImage string, extraAr
|
||||
}
|
||||
|
||||
func (r *vmRunConfig) run(ctx context.Context, args []string, stdout, stderr io.Writer) error {
|
||||
fileCfg, err := config.ApplyInstanceFlag()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if fileCfg.SerialConsole == "disabled" {
|
||||
// The serial console is disabled by default:
|
||||
// https://gokrazy.org/userguide/instance-config/#serialconsole
|
||||
// 'gok vm run' currently launches QEMU such that
|
||||
// there is a serial0 monitor available, but no HDMI.
|
||||
// Hence, print a tip for how to get the serial console to work.
|
||||
log.Printf("")
|
||||
log.Printf(` Tip: Your config.json disables the serial console. Set "SerialConsole": "ttyAMA0,115200", then select View -> serial0 in QEMU to access an interactive shell for debugging.`)
|
||||
log.Printf("")
|
||||
}
|
||||
|
||||
f, err := os.CreateTemp("", "gokrazy-vm")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -241,7 +253,7 @@ func (r *vmRunConfig) run(ctx context.Context, args []string, stdout, stderr io.
|
||||
fdi := f.Name()
|
||||
log.Printf("building disk image")
|
||||
if !r.dry {
|
||||
if err := r.buildFullDiskImage(ctx, fdi); err != nil {
|
||||
if err := r.buildFullDiskImage(ctx, fdi, fileCfg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package packer
|
||||
|
||||
import (
|
||||
"encoding/pem"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/breml/rootcerts/embedded"
|
||||
"golang.org/x/crypto/x509roots/fallback/bundle"
|
||||
)
|
||||
|
||||
func (pack *Pack) findSystemCertsPEM() (string, error) {
|
||||
@@ -14,6 +15,7 @@ func (pack *Pack) findSystemCertsPEM() (string, error) {
|
||||
defer func() {
|
||||
log.Printf("Loading system CA certificates from %s", source)
|
||||
}()
|
||||
|
||||
// On Linux, we can copy the operating system’s certificate store.
|
||||
// certFiles is defined in cacerts_linux.go (or defined as empty in
|
||||
// cacertsstub.go on non-Linux):
|
||||
@@ -37,7 +39,18 @@ func (pack *Pack) findSystemCertsPEM() (string, error) {
|
||||
return string(b), nil
|
||||
}
|
||||
|
||||
// Fall back to github.com/breml/rootcerts, i.e. the bundled Mozilla CA list:
|
||||
source = "bundled Mozilla CA list"
|
||||
return embedded.MozillaCACertificatesPEM(), nil
|
||||
// Fall back to the x/crypto fallback bundle root certificates:
|
||||
source = "bundled x509roots/fallback/bundle"
|
||||
return xrf(), nil
|
||||
}
|
||||
|
||||
func xrf() string {
|
||||
var certs []byte
|
||||
for c := range bundle.Roots() {
|
||||
certs = append(certs, pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: c.Certificate,
|
||||
})...)
|
||||
}
|
||||
return string(certs)
|
||||
}
|
||||
|
||||
@@ -37,6 +37,10 @@ import (
|
||||
"github.com/gokrazy/updater"
|
||||
)
|
||||
|
||||
type contextKey int
|
||||
|
||||
var BuildTimestampOverride contextKey
|
||||
|
||||
const MB = 1024 * 1024
|
||||
|
||||
type filePathAndModTime struct {
|
||||
@@ -1099,7 +1103,7 @@ func filterGoEnv(env []string) []string {
|
||||
return relevant
|
||||
}
|
||||
|
||||
func (pack *Pack) logicPrepare(programName string, sbomHook func(marshaled []byte, withHash SBOMWithHash)) error {
|
||||
func (pack *Pack) logicPrepare(ctx context.Context, programName string, sbomHook func(marshaled []byte, withHash SBOMWithHash)) error {
|
||||
log := pack.Env.Logger()
|
||||
cfg := pack.Cfg
|
||||
updateflag.SetUpdate(cfg.InternalCompatibilityFlags.Update)
|
||||
@@ -1178,6 +1182,9 @@ func (pack *Pack) logicPrepare(programName string, sbomHook func(marshaled []byt
|
||||
log.Printf("Build target: %s", strings.Join(filterGoEnv(packer.Env()), " "))
|
||||
|
||||
pack.buildTimestamp = time.Now().Format(time.RFC3339)
|
||||
if ts, ok := ctx.Value(BuildTimestampOverride).(string); ok {
|
||||
pack.buildTimestamp = ts
|
||||
}
|
||||
log.Printf("Build timestamp: %s", pack.buildTimestamp)
|
||||
|
||||
systemCertsPEM, err := pack.findSystemCertsPEM()
|
||||
@@ -1630,7 +1637,7 @@ func (pack *Pack) logicBuild(programName string, sbomHook func(marshaled []byte,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pack *Pack) logic(programName string, sbomHook func(marshaled []byte, withHash SBOMWithHash)) error {
|
||||
func (pack *Pack) logic(ctx context.Context, programName string, sbomHook func(marshaled []byte, withHash SBOMWithHash)) error {
|
||||
dnsCheck := make(chan error)
|
||||
go func() {
|
||||
defer close(dnsCheck)
|
||||
@@ -1646,7 +1653,7 @@ func (pack *Pack) logic(programName string, sbomHook func(marshaled []byte, with
|
||||
dnsCheck <- nil
|
||||
}()
|
||||
|
||||
if err := pack.logicPrepare(programName, sbomHook); err != nil {
|
||||
if err := pack.logicPrepare(ctx, programName, sbomHook); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1669,6 +1676,7 @@ func (pack *Pack) logic(programName string, sbomHook func(marshaled []byte, with
|
||||
}
|
||||
|
||||
func (pack *Pack) logicWrite(programName string, sbomHook func(marshaled []byte, withHash SBOMWithHash), bindir string, dnsCheck chan error) error {
|
||||
ctx := context.Background()
|
||||
log := pack.Env.Logger()
|
||||
|
||||
var (
|
||||
@@ -1718,7 +1726,7 @@ func (pack *Pack) logicWrite(programName string, sbomHook func(marshaled []byte,
|
||||
}
|
||||
updateBaseUrl.Path = "/"
|
||||
|
||||
target, err = updater.NewTarget(updateBaseUrl.String(), updateHttpClient)
|
||||
target, err = updater.NewTarget(ctx, updateBaseUrl.String(), updateHttpClient)
|
||||
if err != nil {
|
||||
return fmt.Errorf("checking target partuuid support: %v", err)
|
||||
}
|
||||
@@ -2035,7 +2043,7 @@ func (pack *Pack) logicWrite(programName string, sbomHook func(marshaled []byte,
|
||||
return err
|
||||
}
|
||||
|
||||
if err := target.StreamTo("mbr", mbrReader); err != nil {
|
||||
if err := target.StreamTo(ctx, "mbr", mbrReader); err != nil {
|
||||
if err == updater.ErrUpdateHandlerNotImplemented {
|
||||
log.Printf("target does not support updating MBR yet, ignoring")
|
||||
} else {
|
||||
@@ -2044,11 +2052,11 @@ func (pack *Pack) logicWrite(programName string, sbomHook func(marshaled []byte,
|
||||
}
|
||||
|
||||
if cfg.InternalCompatibilityFlags.Testboot {
|
||||
if err := target.Testboot(); err != nil {
|
||||
if err := target.Testboot(ctx); err != nil {
|
||||
return fmt.Errorf("enable testboot of non-active partition: %v", err)
|
||||
}
|
||||
} else {
|
||||
if err := target.Switch(); err != nil {
|
||||
if err := target.Switch(ctx); err != nil {
|
||||
return fmt.Errorf("switching to non-active partition: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -2057,7 +2065,7 @@ func (pack *Pack) logicWrite(programName string, sbomHook func(marshaled []byte,
|
||||
canc()
|
||||
|
||||
log.Printf("Triggering reboot")
|
||||
if err := target.Reboot(); err != nil {
|
||||
if err := target.Reboot(ctx); err != nil {
|
||||
if errors.Is(err, syscall.ECONNRESET) {
|
||||
log.Printf("ignoring reboot error: %v", err)
|
||||
} else {
|
||||
@@ -2159,6 +2167,7 @@ func (pack *Pack) validateTargetArchMatchesKernel() error {
|
||||
}
|
||||
|
||||
func (pack *Pack) updateWithProgress(prog *progress.Reporter, reader io.Reader, target *updater.Target, logStr string, stream string) error {
|
||||
ctx := context.Background()
|
||||
log := pack.Env.Logger()
|
||||
|
||||
start := time.Now()
|
||||
@@ -2170,7 +2179,7 @@ func (pack *Pack) updateWithProgress(prog *progress.Reporter, reader io.Reader,
|
||||
prog.SetTotal(uint64(st.Size()))
|
||||
}
|
||||
}
|
||||
if err := target.StreamTo(stream, io.TeeReader(reader, &progress.Writer{})); err != nil {
|
||||
if err := target.StreamTo(ctx, stream, io.TeeReader(reader, &progress.Writer{})); err != nil {
|
||||
return fmt.Errorf("updating %s: %w", logStr, err)
|
||||
}
|
||||
duration := time.Since(start)
|
||||
@@ -2184,17 +2193,17 @@ func (pack *Pack) updateWithProgress(prog *progress.Reporter, reader io.Reader,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pack *Pack) Main(programName string) {
|
||||
if err := pack.logic(programName, nil); err != nil {
|
||||
func (pack *Pack) Main(ctx context.Context, programName string) {
|
||||
if err := pack.logic(ctx, programName, nil); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "ERROR:\n %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (pack *Pack) GenerateSBOM() ([]byte, SBOMWithHash, error) {
|
||||
func (pack *Pack) GenerateSBOM(ctx context.Context) ([]byte, SBOMWithHash, error) {
|
||||
var sbom []byte
|
||||
var sbomWithHash SBOMWithHash
|
||||
if err := pack.logic("gokrazy gok", func(b []byte, wh SBOMWithHash) {
|
||||
if err := pack.logic(ctx, "gokrazy gok", func(b []byte, wh SBOMWithHash) {
|
||||
sbom = b
|
||||
sbomWithHash = wh
|
||||
}); err != nil {
|
||||
|
||||
@@ -19,7 +19,7 @@ func pollUpdated1(ctx context.Context, updateHttpClient *http.Client, updateBase
|
||||
return err
|
||||
}
|
||||
req = req.WithContext(ctx)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Accept", "application/json")
|
||||
resp, err := updateHttpClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user