diff --git a/.github/workflows/osv-scanner-pr.yaml b/.github/workflows/osv-scanner-pr.yaml index defa6d0..2903c0c 100644 --- a/.github/workflows/osv-scanner-pr.yaml +++ b/.github/workflows/osv-scanner-pr.yaml @@ -18,4 +18,4 @@ permissions: jobs: scan-pr: - uses: "google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@v1.8.5" + uses: "google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@v1.9.0" diff --git a/.github/workflows/secscan.yaml b/.github/workflows/secscan.yaml index 7ddd308..e2159ee 100644 --- a/.github/workflows/secscan.yaml +++ b/.github/workflows/secscan.yaml @@ -19,7 +19,7 @@ jobs: - name: Checkout Source uses: actions/checkout@v4 - name: Run Gosec Security Scanner - uses: securego/gosec@v2.21.2 + uses: securego/gosec@v2.21.4 with: # we let the report trigger content trigger a failure using the GitHub Security features. args: '-no-fail -fmt sarif -out results.sarif ./...' diff --git a/go.mod b/go.mod index 26388b6..1d4cb90 100644 --- a/go.mod +++ b/go.mod @@ -12,14 +12,14 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/jaypipes/ghw v0.13.0 // indirect github.com/joho/godotenv v1.5.1 - github.com/kairos-io/kairos-sdk v0.4.5 + github.com/kairos-io/kairos-sdk v0.6.0 github.com/kairos-io/kcrypt v0.12.2 github.com/labstack/echo/v4 v4.12.0 github.com/mitchellh/mapstructure v1.5.0 github.com/mudler/go-nodepair v0.0.0-20221223092639-ba399a66fdfb github.com/mudler/go-pluggable v0.0.0-20230126220627-7710299a0ae5 github.com/mudler/go-processmanager v0.0.0-20240820160718-8b802d3ecf82 - github.com/mudler/yip v1.9.4 + github.com/mudler/yip v1.11.0 github.com/nxadm/tail v1.4.11 github.com/onsi/ginkgo/v2 v2.20.2 github.com/onsi/gomega v1.34.2 @@ -41,8 +41,6 @@ require ( github.com/gofrs/uuid v4.4.0+incompatible github.com/google/go-github/v63 v63.0.0 github.com/twpayne/go-vfs/v4 v4.3.0 - github.com/google/go-github/v65 v65.0.0 - github.com/twpayne/go-vfs/v5 v5.0.4 ) require ( @@ -84,7 +82,7 @@ require ( github.com/djherbis/times v1.6.0 // indirect github.com/docker/cli v27.1.1+incompatible // indirect github.com/docker/distribution v2.8.2+incompatible // indirect - github.com/docker/docker v27.2.1+incompatible // indirect + github.com/docker/docker v27.3.1+incompatible // indirect github.com/docker/docker-credential-helpers v0.7.0 // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect @@ -205,7 +203,7 @@ require ( github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - github.com/zcalusic/sysinfo v1.1.0 // indirect + github.com/zcalusic/sysinfo v1.1.2 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect @@ -228,7 +226,6 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect - gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect howett.net/plist v1.0.0 // indirect k8s.io/klog/v2 v2.130.1 // indirect diff --git a/go.sum b/go.sum index ded597d..6524a1e 100644 --- a/go.sum +++ b/go.sum @@ -131,8 +131,8 @@ github.com/docker/cli v27.1.1+incompatible h1:goaZxOqs4QKxznZjjBWKONQci/MywhtRv2 github.com/docker/cli v27.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v27.2.1+incompatible h1:fQdiLfW7VLscyoeYEBz7/J8soYFDZV1u6VW6gJEjNMI= -github.com/docker/docker v27.2.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI= +github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= @@ -230,7 +230,6 @@ github.com/google/go-containerregistry v0.20.2 h1:B1wPJ1SN/S7pB+ZAimcciVD+r+yV/l github.com/google/go-containerregistry v0.20.2/go.mod h1:z38EKdKh4h7IP2gSfUUqEvalZBqs6AoLeWfUy34nQC8= github.com/google/go-github/v63 v63.0.0 h1:13xwK/wk9alSokujB9lJkuzdmQuVn2QCPeck76wR3nE= github.com/google/go-github/v63 v63.0.0/go.mod h1:IqbcrgUmIcEaioWrGYei/09o+ge5vhffGOcxrO0AfmA= -github.com/google/go-github/v65 v65.0.0/go.mod h1:DvrqWo5hvsdhJvHd4WyVF9ttANN3BniqjP8uTFMNb60= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA= @@ -277,14 +276,10 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 h1:G+9t9cEtnC9jFiTxyptEKuNIAbiN5ZCQzX2a74lj3xg= github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004/go.mod h1:KmHnJWQrgEvbuy0vcvj00gtMqbvNn1L+3YUZLK/B92c= -github.com/kairos-io/kairos-sdk v0.4.3 h1:gIC/PsWjv9/Z+6RIHRG9IS5MB9gACw1ZjPAi7VydSSo= -github.com/kairos-io/kairos-sdk v0.4.3/go.mod h1:bxUPzirl8vNtqB48FJ2835QKio3d3PrHbkAejkibV8I= -github.com/kairos-io/kairos-sdk v0.4.4-0.20240912144533-f312c84d81be h1:cY33zv58Ejwn6u0nBp0ALJYNKlLPD534HHO6SQ6lksk= -github.com/kairos-io/kairos-sdk v0.4.4-0.20240912144533-f312c84d81be/go.mod h1:fPLrvHAStnKR1wGGyNj61prnYsC9QNQCNxnKe/49H54= -github.com/kairos-io/kairos-sdk v0.4.4 h1:FolUGqpdTnYYdLwFEOND97QEp2H/htVjW7pHUOmtxNI= -github.com/kairos-io/kairos-sdk v0.4.4/go.mod h1:OIJYihhuiUOeBXHYj9V3R381SAgc/EaKrFepcBxGroM= -github.com/kairos-io/kairos-sdk v0.4.5 h1:ja3GBPODLPx4X/9dEALncpDIHvFH8TdEBMda0H6O49o= -github.com/kairos-io/kairos-sdk v0.4.5/go.mod h1:OIJYihhuiUOeBXHYj9V3R381SAgc/EaKrFepcBxGroM= +github.com/kairos-io/kairos-sdk v0.4.6 h1:6dbKozJTku99P2vytz9M0xAnpkKKiAggSMPfT2vpw68= +github.com/kairos-io/kairos-sdk v0.4.6/go.mod h1:QXYmZ2BMrJ0Iyp7I3+rvCYpZRMvwOtK/6IGCLhNL4tY= +github.com/kairos-io/kairos-sdk v0.6.0 h1:A096lZVHE4rkvA5kG0Oss0085T0noUcf7AeppWGySR8= +github.com/kairos-io/kairos-sdk v0.6.0/go.mod h1:7Y6Y/McniCyAJcmQfoTfKd09cwmwS40URaIVbJn8V2k= github.com/kairos-io/kcrypt v0.12.2 h1:+lr8FGS0AW6D5dWSmaR3+AobL1TBTnOFgCSYctKY+5I= github.com/kairos-io/kcrypt v0.12.2/go.mod h1:7SPiHzNMYl4MlxeB30s1YlHDYByTusu7u1mU5Nvicm0= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= @@ -370,8 +365,10 @@ github.com/mudler/go-pluggable v0.0.0-20230126220627-7710299a0ae5 h1:FaZD86+A9mV github.com/mudler/go-pluggable v0.0.0-20230126220627-7710299a0ae5/go.mod h1:WmKcT8ONmhDQIqQ+HxU+tkGWjzBEyY/KFO8LTGCu4AI= github.com/mudler/go-processmanager v0.0.0-20240820160718-8b802d3ecf82 h1:FVT07EI8njvsD4tC2Hw8Xhactp5AWhsQWD4oTeQuSAU= github.com/mudler/go-processmanager v0.0.0-20240820160718-8b802d3ecf82/go.mod h1:Urp7LG5jylKoDq0663qeBh0pINGcRl35nXdKx82PSoU= -github.com/mudler/yip v1.9.4 h1:yaiPKWG5kt/DTNCf7ZGfyWdb1j5c06zYqWF3F+SVKsE= -github.com/mudler/yip v1.9.4/go.mod h1:nqf8JFCq7a7rIkm7cSs+SOc8QbiyvVJ/xLbUw4GgzFs= +github.com/mudler/yip v1.10.0 h1:MwEIySEfSRRwTUz2BmQQpRn6+M7jqVGf/OldsepBvz0= +github.com/mudler/yip v1.10.0/go.mod h1:gwH7iGcr1Jimox2xKtN2AprEO00GzY7smvuycqCL7+Y= +github.com/mudler/yip v1.11.0 h1:h+npjzSKM9VbShHxa+ywWZzpGIolKvN/e2FOT+rxKkI= +github.com/mudler/yip v1.11.0/go.mod h1:gwH7iGcr1Jimox2xKtN2AprEO00GzY7smvuycqCL7+Y= github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= @@ -536,7 +533,6 @@ github.com/tredoe/osutil v1.5.0 h1:UGVxbbHRoZi8xXVmbNZ2vgG6XoJ15ndE4LniiQ3rJKg= github.com/tredoe/osutil v1.5.0/go.mod h1:TEzphzUUunysbdDRfdOgqkg10POQbnfIPV50ynqOfIg= github.com/twpayne/go-vfs/v4 v4.3.0 h1:rTqFzzOQ/6ESKTSiwVubHlCBedJDOhQyVSnw8rQNZhU= github.com/twpayne/go-vfs/v4 v4.3.0/go.mod h1:tq2UVhnUepesc0lSnPJH/jQ8HruGhzwZe2r5kDFpEIw= -github.com/twpayne/go-vfs/v5 v5.0.4/go.mod h1:zTPFJUbgsEMFNSWnWQlLq9wh4AN83edZzx3VXbxrS1w= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= @@ -573,8 +569,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -github.com/zcalusic/sysinfo v1.1.0 h1:79Hqn8h4poVz6T57/4ezXbT5ZkZbZm7u1YU1C4paMyk= -github.com/zcalusic/sysinfo v1.1.0/go.mod h1:NX+qYnWGtJVPV0yWldff9uppNKU4h40hJIRPf/pGLv4= +github.com/zcalusic/sysinfo v1.1.2 h1:38KUgZQmCxlN9vUTt4miis4rU5ISJXGXOJ2rY7bMC8g= +github.com/zcalusic/sysinfo v1.1.2/go.mod h1:NX+qYnWGtJVPV0yWldff9uppNKU4h40hJIRPf/pGLv4= go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 h1:A/5uWzF44DlIgdm/PQFwfMkW0JX+cIcQi/SwLAmZP5M= go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= @@ -780,7 +776,6 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU= gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -799,8 +794,6 @@ howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/mount-utils v0.31.0 h1:o+a+n6gyZ7MGc6bIERU3LeFTHbLDBiVReaDpWlJotUE= -k8s.io/mount-utils v0.31.0/go.mod h1:HV/VYBUGqYUj4vt82YltzpWvgv8FPg0G9ItyInT3NPU= k8s.io/mount-utils v0.31.1 h1:f8UrH9kRynljmdNGM6BaCvFUON5ZPKDgE+ltmYqI4wA= k8s.io/mount-utils v0.31.1/go.mod h1:HV/VYBUGqYUj4vt82YltzpWvgv8FPg0G9ItyInT3NPU= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= diff --git a/internal/agent/agent.go b/internal/agent/agent.go index 18160ce..a8875b8 100644 --- a/internal/agent/agent.go +++ b/internal/agent/agent.go @@ -2,6 +2,8 @@ package agent import ( "fmt" + "os" + hook "github.com/kairos-io/kairos-agent/v2/internal/agent/hooks" "github.com/kairos-io/kairos-agent/v2/internal/bus" config "github.com/kairos-io/kairos-agent/v2/pkg/config" @@ -10,7 +12,6 @@ import ( "github.com/kairos-io/kairos-sdk/collector" "github.com/kairos-io/kairos-sdk/machine" "github.com/kairos-io/kairos-sdk/utils" - "os" ) // Run starts the agent provider emitting the bootstrap event. @@ -37,7 +38,7 @@ func Run(opts ...Option) error { } fileName := "/var/log/kairos/agent-provider.log" - + if !machine.SentinelExist("firstboot") { spec := v1.EmptySpec{} if err := hook.Run(*c, &spec, hook.FirstBoot...); err != nil { diff --git a/internal/agent/upgrade.go b/internal/agent/upgrade.go index c9ef518..1633996 100644 --- a/internal/agent/upgrade.go +++ b/internal/agent/upgrade.go @@ -23,7 +23,7 @@ import ( func CurrentImage() (string, error) { artifact, err := versioneer.NewArtifactFromOSRelease() if err != nil { - return "", fmt.Errorf("creating an Artifact from os-release: %w", err) + return "", fmt.Errorf("creating an Artifact from kairos-release: %w", err) } registryAndOrg, err := utils.OSRelease("REGISTRY_AND_ORG") diff --git a/internal/webui/public/package-lock.json b/internal/webui/public/package-lock.json index 651907a..935a5de 100644 --- a/internal/webui/public/package-lock.json +++ b/internal/webui/public/package-lock.json @@ -31,9 +31,9 @@ } }, "node_modules/@cypress/request": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz", - "integrity": "sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.5.tgz", + "integrity": "sha512-v+XHd9XmWbufxF1/bTaVm2yhbxY+TB4YtWRqF2zaXBlDNMkls34KiATz0AVDLavL3iB6bQk9/7n3oY1EoLSWGA==", "dev": true, "dependencies": { "aws-sign2": "~0.7.0", @@ -42,14 +42,14 @@ "combined-stream": "~1.0.6", "extend": "~3.0.2", "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "http-signature": "~1.3.6", + "form-data": "~4.0.0", + "http-signature": "~1.4.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "performance-now": "^2.1.0", - "qs": "6.10.4", + "qs": "6.13.0", "safe-buffer": "^5.1.2", "tough-cookie": "^4.1.3", "tunnel-agent": "^0.6.0", @@ -413,13 +413,19 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -620,13 +626,13 @@ } }, "node_modules/cypress": { - "version": "13.14.2", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.14.2.tgz", - "integrity": "sha512-lsiQrN17vHMB2fnvxIrKLAjOr9bPwsNbPZNrWf99s4u+DVmCY6U+w7O3GGG9FvP4EUVYaDu+guWeNLiUzBrqvA==", + "version": "13.15.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.15.0.tgz", + "integrity": "sha512-53aO7PwOfi604qzOkCSzNlWquCynLlKE/rmmpSPcziRH6LNfaDUAklQT6WJIsD8ywxlIy+uVZsnTMCCQVd2kTw==", "dev": true, "hasInstallScript": true, "dependencies": { - "@cypress/request": "^3.0.1", + "@cypress/request": "^3.0.4", "@cypress/xvfb": "^1.2.4", "@types/sinonjs__fake-timers": "8.1.1", "@types/sizzle": "^2.3.2", @@ -711,6 +717,23 @@ } } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -757,6 +780,27 @@ "node": ">=8.6" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -876,17 +920,17 @@ } }, "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dev": true, "dependencies": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", + "combined-stream": "^1.0.8", "mime-types": "^2.1.12" }, "engines": { - "node": ">= 0.12" + "node": ">= 6" } }, "node_modules/fs-extra": { @@ -910,20 +954,28 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/get-intrinsic": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", - "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -996,24 +1048,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -1023,6 +1075,30 @@ "node": ">=8" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -1035,15 +1111,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/http-signature": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", - "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.4.0.tgz", + "integrity": "sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg==", "dev": true, "dependencies": { "assert-plus": "^1.0.0", "jsprim": "^2.0.2", - "sshpk": "^1.14.1" + "sshpk": "^1.18.0" }, "engines": { "node": ">=0.10" @@ -1448,10 +1536,13 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -1591,12 +1682,12 @@ } }, "node_modules/qs": { - "version": "6.10.4", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", - "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -1695,6 +1786,23 @@ "node": ">=10" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -1717,14 +1825,18 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1756,9 +1868,9 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, "node_modules/sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", "dev": true, "dependencies": { "asn1": "~0.2.3", @@ -2056,9 +2168,9 @@ "optional": true }, "@cypress/request": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz", - "integrity": "sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.5.tgz", + "integrity": "sha512-v+XHd9XmWbufxF1/bTaVm2yhbxY+TB4YtWRqF2zaXBlDNMkls34KiATz0AVDLavL3iB6bQk9/7n3oY1EoLSWGA==", "dev": true, "requires": { "aws-sign2": "~0.7.0", @@ -2067,14 +2179,14 @@ "combined-stream": "~1.0.6", "extend": "~3.0.2", "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "http-signature": "~1.3.6", + "form-data": "~4.0.0", + "http-signature": "~1.4.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "performance-now": "^2.1.0", - "qs": "6.10.4", + "qs": "6.13.0", "safe-buffer": "^5.1.2", "tough-cookie": "^4.1.3", "tunnel-agent": "^0.6.0", @@ -2337,13 +2449,16 @@ "dev": true }, "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" } }, "caseless": { @@ -2490,12 +2605,12 @@ } }, "cypress": { - "version": "13.14.2", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.14.2.tgz", - "integrity": "sha512-lsiQrN17vHMB2fnvxIrKLAjOr9bPwsNbPZNrWf99s4u+DVmCY6U+w7O3GGG9FvP4EUVYaDu+guWeNLiUzBrqvA==", + "version": "13.15.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.15.0.tgz", + "integrity": "sha512-53aO7PwOfi604qzOkCSzNlWquCynLlKE/rmmpSPcziRH6LNfaDUAklQT6WJIsD8ywxlIy+uVZsnTMCCQVd2kTw==", "dev": true, "requires": { - "@cypress/request": "^3.0.1", + "@cypress/request": "^3.0.4", "@cypress/xvfb": "^1.2.4", "@types/sinonjs__fake-timers": "8.1.1", "@types/sizzle": "^2.3.2", @@ -2563,6 +2678,17 @@ "ms": "2.1.2" } }, + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -2603,6 +2729,21 @@ "ansi-colors": "^4.1.1" } }, + "es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.4" + } + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -2690,13 +2831,13 @@ "dev": true }, "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dev": true, "requires": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", + "combined-stream": "^1.0.8", "mime-types": "^2.1.12" } }, @@ -2718,20 +2859,22 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true }, "get-intrinsic": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", - "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" } }, "get-stream": { @@ -2783,42 +2926,66 @@ "ini": "2.0.0" } }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0" + } + }, + "has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true + }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + } + }, "http-signature": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", - "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.4.0.tgz", + "integrity": "sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg==", "dev": true, "requires": { "assert-plus": "^1.0.0", "jsprim": "^2.0.2", - "sshpk": "^1.14.1" + "sshpk": "^1.18.0" } }, "human-signals": { @@ -3111,9 +3278,9 @@ } }, "object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true }, "once": { @@ -3218,12 +3385,12 @@ "dev": true }, "qs": { - "version": "6.10.4", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", - "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "requires": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" } }, "querystringify": { @@ -3293,6 +3460,20 @@ "lru-cache": "^6.0.0" } }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + } + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -3309,14 +3490,15 @@ "dev": true }, "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" } }, "signal-exit": { @@ -3342,9 +3524,9 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, "sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", "dev": true, "requires": { "asn1": "~0.2.3", diff --git a/main.go b/main.go index 0cae858..4a99c93 100644 --- a/main.go +++ b/main.go @@ -227,7 +227,7 @@ See https://kairos.io/docs/upgrade/manual/ for documentation. } return agent.Upgrade(source, c.Bool("force"), - c.Bool("strict-validation"), constants.GetConfigScanDirs(), + c.Bool("strict-validation"), constants.GetUserConfigDirs(), upgradeEntry, c.Bool("pre"), ) }, @@ -356,14 +356,14 @@ E.g. kairos-agent install-bundle container:quay.io/kairos/kairos... Description: "Show the runtime configuration of the machine. It will scan the machine for all the configuration and will return the config file processed and found.", Aliases: []string{"c"}, Action: func(c *cli.Context) error { - config, err := agentConfig.Scan(collector.Directories(constants.GetConfigScanDirs()...), collector.NoLogs) + config, err := agentConfig.Scan(collector.Directories(constants.GetUserConfigDirs()...), collector.NoLogs) if err != nil { return err } configStr, err := config.String() if err != nil { - return err + return fmt.Errorf("getting config string: %w", err) } fmt.Printf("%s", configStr) return nil @@ -375,7 +375,7 @@ E.g. kairos-agent install-bundle container:quay.io/kairos/kairos... Description: "WARNING this command will be deprecated in v3.2.0. Use `config` without a subcommand instead.\n\n Show the runtime configuration of the machine. It will scan the machine for all the configuration and will return the config file processed and found.", Aliases: []string{}, Action: func(c *cli.Context) error { - config, err := agentConfig.Scan(collector.Directories(constants.GetConfigScanDirs()...), collector.NoLogs) + config, err := agentConfig.Scan(collector.Directories(constants.GetUserConfigDirs()...), collector.NoLogs) if err != nil { return err } @@ -404,7 +404,7 @@ enabled: true`, Description: "It allows to navigate the YAML config file by searching with 'yq' style keywords as `config get k3s` to retrieve the k3s config block", Aliases: []string{"g"}, Action: func(c *cli.Context) error { - config, err := agentConfig.ScanNoLogs(collector.Directories(constants.GetConfigScanDirs()...), collector.NoLogs, collector.StrictValidation(c.Bool("strict-validation"))) + config, err := agentConfig.ScanNoLogs(collector.Directories(constants.GetUserConfigDirs()...), collector.NoLogs, collector.StrictValidation(c.Bool("strict-validation"))) if err != nil { return err } @@ -475,7 +475,7 @@ enabled: true`, }, Action: func(c *cli.Context) error { - config, err := agentConfig.ScanNoLogs(collector.Directories(constants.GetConfigScanDirs()...), collector.NoLogs, collector.StrictValidation(c.Bool("strict-validation"))) + config, err := agentConfig.ScanNoLogs(collector.Directories(constants.GetUserConfigDirs()...), collector.NoLogs, collector.StrictValidation(c.Bool("strict-validation"))) if err != nil { return err } @@ -585,7 +585,7 @@ This command is meant to be used from the boot GRUB menu, but can be started man Action: func(c *cli.Context) error { source := c.String("source") - return agent.Install(source, constants.GetConfigScanDirs()...) + return agent.Install(source, constants.GetUserConfigDirs()...) }, }, { @@ -629,7 +629,7 @@ This command is meant to be used from the boot GRUB menu, but can likely be used unattended := c.Bool("unattended") resetOem := c.Bool("reset-oem") - return agent.Reset(reboot, unattended, resetOem, constants.GetConfigScanDirs()...) + return agent.Reset(reboot, unattended, resetOem, constants.GetUserConfigDirs()...) }, Usage: "Starts kairos reset mode", Description: ` @@ -713,7 +713,7 @@ The validate command expects a configuration file as its only argument. Local fi }, Action: func(c *cli.Context) error { stage := c.Args().First() - config, err := agentConfig.Scan(collector.Directories(constants.GetConfigScanDirs()...), collector.NoLogs) + config, err := agentConfig.Scan(collector.Directories(constants.GetYipConfigDirs()...), collector.NoLogs) config.Strict = c.Bool("strict") if len(c.StringSlice("cloud-init-paths")) > 0 { @@ -759,7 +759,7 @@ The validate command expects a configuration file as its only argument. Local fi if err != nil { return fmt.Errorf("invalid path %s", destination) } - config, err := agentConfig.Scan(collector.Directories(constants.GetConfigScanDirs()...), collector.NoLogs) + config, err := agentConfig.Scan(collector.Directories(constants.GetUserConfigDirs()...), collector.NoLogs) if err != nil { return err } @@ -813,7 +813,7 @@ The validate command expects a configuration file as its only argument. Local fi return checkRoot() }, Action: func(c *cli.Context) error { - cfg, err := agentConfig.Scan(collector.Directories(constants.GetConfigScanDirs()...), collector.NoLogs) + cfg, err := agentConfig.Scan(collector.Directories(constants.GetUserConfigDirs()...), collector.NoLogs) if err != nil { return err } diff --git a/pkg/action/render_template.go b/pkg/action/render_template.go index ed3deaa..2716a82 100644 --- a/pkg/action/render_template.go +++ b/pkg/action/render_template.go @@ -26,7 +26,7 @@ func RenderTemplate(path string, config *config.Config, runtime state.Runtime) ( result := new(bytes.Buffer) err = tpl.Execute(result, map[string]interface{}{ - "Config": config.Config, + "Config": config.Config.Values, "State": runtimeMap, }) if err != nil { diff --git a/pkg/action/render_template_test.go b/pkg/action/render_template_test.go index ce2bf01..37b9f4a 100644 --- a/pkg/action/render_template_test.go +++ b/pkg/action/render_template_test.go @@ -14,7 +14,9 @@ var _ = Describe("RenderTemplate action test", func() { It("renders the template with config and state", func() { config := agentConfig.NewConfig() config.Config = collector.Config{ - "testKey": "testValue", + Values: collector.ConfigValues{ + "testKey": "testValue", + }, } runtime, err := state.NewRuntime() Expect(err).ToNot(HaveOccurred()) diff --git a/pkg/action/reset.go b/pkg/action/reset.go index b382a5f..feb515e 100644 --- a/pkg/action/reset.go +++ b/pkg/action/reset.go @@ -113,24 +113,38 @@ func (r ResetAction) Run() (err error) { cleanup := utils.NewCleanStack() defer func() { err = cleanup.Cleanup(err) }() - // Unmount partitions if any is already mounted before formatting - // TODO: Is this needed??? - err = e.UnmountPartitions(r.spec.Partitions.PartitionsByMountPoint(true, r.spec.Partitions.Recovery)) - if err != nil { - return err - } - // Reformat state partition - err = e.FormatPartition(r.spec.Partitions.State) - if err != nil { - return err - } + // We should expose this under a flag, to reformat state before starting + // In case state fs is broken somehow + // We used to format it blindly but if something happens between this format and the new image copy down below + // You end up with a broken system with no active or passive and reset may not even work at that point + // TODO: Either create a flag to do this or ignore it and never format the partition + /* + if r.spec.FormatState { + state := r.spec.Partitions.State + if state != nil { + err = e.UnmountPartition(state) + if err != nil { + return err + } + err = e.FormatPartition(state) + if err != nil { + return err + } + // Mount it back + err = e.MountPartition(state) + if err != nil { + return err + } + } + } + */ // Reformat persistent partition if r.spec.FormatPersistent { persistent := r.spec.Partitions.Persistent if persistent != nil { - err = e.UnmountPartitions(r.spec.Partitions.PartitionsByMountPoint(true, persistent)) + err = e.UnmountPartition(persistent) if err != nil { return err } @@ -146,7 +160,7 @@ func (r ResetAction) Run() (err error) { oem := r.spec.Partitions.OEM if oem != nil { // Try to umount - err = e.UnmountPartitions(r.spec.Partitions.PartitionsByMountPoint(true, oem)) + err = e.UnmountPartition(oem) if err != nil { return err } @@ -154,16 +168,13 @@ func (r ResetAction) Run() (err error) { if err != nil { return err } + // Mount it back, as oem is mounted during recovery, keep everything as is + err = e.MountPartition(oem) + if err != nil { + return err + } } } - // Mount configured partitions - err = e.MountPartitions(r.spec.Partitions.PartitionsByMountPoint(false, r.spec.Partitions.Recovery)) - if err != nil { - return err - } - cleanup.Push(func() error { - return e.UnmountPartitions(r.spec.Partitions.PartitionsByMountPoint(true, r.spec.Partitions.Recovery)) - }) // Before reset hook happens once partitions are aready and before deploying the OS image err = r.resetHook(cnst.BeforeResetHook, false) @@ -171,6 +182,13 @@ func (r ResetAction) Run() (err error) { return err } + // Mount COS_STATE so we can write the new images + err = e.MountPartition(r.spec.Partitions.State) + if err != nil { + return err + } + cleanup.Push(func() error { return e.UnmountPartition(r.spec.Partitions.State) }) + // Deploy active image meta, err := e.DeployImage(&r.spec.Active, true) if err != nil { diff --git a/pkg/action/reset_test.go b/pkg/action/reset_test.go index fc1531c..8473cbc 100644 --- a/pkg/action/reset_test.go +++ b/pkg/action/reset_test.go @@ -89,7 +89,6 @@ var _ = Describe("Reset action tests", func() { var cmdFail, bootedFrom string var err error BeforeEach(func() { - Expect(err).ShouldNot(HaveOccurred()) cmdFail = "" recoveryImg := filepath.Join(constants.RunningStateDir, "cOS", constants.RecoveryImgFile) @@ -108,22 +107,24 @@ var _ = Describe("Reset action tests", func() { }, { Name: "device2", + FilesystemLabel: "COS_OEM", + FS: "ext4", + MountPoint: "/oem", + }, + { + Name: "device3", + FilesystemLabel: "COS_RECOVERY", + FS: "ext4", + MountPoint: "/run/initramfs/cos-state", + }, + { + Name: "device4", FilesystemLabel: "COS_STATE", FS: "ext4", }, - { - Name: "device3", - FilesystemLabel: "COS_PERSISTENT", - FS: "ext4", - }, - { - Name: "device4", - FilesystemLabel: "COS_OEM", - FS: "ext4", - }, { Name: "device5", - FilesystemLabel: "COS_RECOVERY", + FilesystemLabel: "COS_PERSISTENT", FS: "ext4", }, }, diff --git a/pkg/action/upgrade_test.go b/pkg/action/upgrade_test.go index 98ea6f8..3cea382 100644 --- a/pkg/action/upgrade_test.go +++ b/pkg/action/upgrade_test.go @@ -198,7 +198,7 @@ var _ = Describe("Upgrade Actions test", func() { Expect(err).ShouldNot(HaveOccurred()) err = fs.WriteFile( - filepath.Join(spec.Active.MountPoint, "etc", "os-release"), + filepath.Join(spec.Active.MountPoint, "etc", "kairos-release"), []byte("GRUB_ENTRY_NAME=TESTOS"), constants.FilePerm, ) @@ -253,7 +253,7 @@ var _ = Describe("Upgrade Actions test", func() { err := upgrade.Run() Expect(err).ToNot(HaveOccurred()) - // Check that the rebrand worked with our os-release value + // Check that the rebrand worked with our kairos-release value Expect(memLog).To(ContainSubstring("Setting default grub entry to TESTOS"), memLog.String()) // This should be the new image @@ -285,7 +285,7 @@ var _ = Describe("Upgrade Actions test", func() { err := upgrade.Run() Expect(err).ToNot(HaveOccurred()) By("Checking the log") - // Check that the rebrand worked with our os-release value + // Check that the rebrand worked with our kairos-release value Expect(memLog).To(ContainSubstring("Setting default grub entry to TESTOS")) By("checking active image") @@ -319,7 +319,7 @@ var _ = Describe("Upgrade Actions test", func() { err := upgrade.Run() Expect(err).ToNot(HaveOccurred()) - // Check that the rebrand worked with our os-release value + // Check that the rebrand worked with our kairos-release value Expect(memLog).To(ContainSubstring("Setting default grub entry to TESTOS")) // This should be the new image @@ -357,7 +357,7 @@ var _ = Describe("Upgrade Actions test", func() { err = upgrade.Run() Expect(err).ToNot(HaveOccurred()) - // Check that the rebrand worked with our os-release value + // Check that the rebrand worked with our kairos-release value Expect(memLog).To(ContainSubstring("Setting default grub entry to TESTOS")) // Not much that we can create here as the dir copy was done on the real os, but we do the rest of the ops on a mem one @@ -395,7 +395,7 @@ var _ = Describe("Upgrade Actions test", func() { Expect(err).ShouldNot(HaveOccurred()) err = fs.WriteFile( - filepath.Join(spec.Active.MountPoint, "etc", "os-release"), + filepath.Join(spec.Active.MountPoint, "etc", "kairos-release"), []byte("GRUB_ENTRY_NAME=TESTOS"), constants.FilePerm, ) @@ -445,7 +445,7 @@ var _ = Describe("Upgrade Actions test", func() { err := upgrade.Run() Expect(err).ToNot(HaveOccurred()) - // Check that the rebrand worked with our os-release value + // Check that the rebrand worked with our kairos-release value Expect(memLog).To(ContainSubstring("Setting default grub entry to TESTOS")) // This should be the new image diff --git a/pkg/config/config.go b/pkg/config/config.go index 131a68a..beb213b 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -408,7 +408,7 @@ func scan(result *Config, opts ...collector.Option) (c *Config, err error) { result.Logger.Logger.Info().Interface("version", version.GetVersion()).Msg("Kairos Agent") result.Logger.Logger.Debug().Interface("version", version.Get()).Msg("Kairos Agent") - // Try to load the kairos version from the os-release file + // Try to load the kairos version from the kairos-release file // Best effort, if it fails, we just ignore it f, err := result.Fs.Open("/etc/os-release") defer f.Close() @@ -417,6 +417,17 @@ func scan(result *Config, opts ...collector.Option) (c *Config, err error) { v := osRelease["KAIROS_VERSION"] if v != "" { result.Logger.Logger.Info().Str("version", v).Msg("Kairos System") + } else { + // Fallback into os-release + f, err = result.Fs.Open("/etc/os-release") + defer f.Close() + osRelease, err = godotenv.Parse(f) + if err == nil { + v = osRelease["KAIROS_VERSION"] + if v != "" { + result.Logger.Logger.Info().Str("version", v).Msg("Kairos System") + } + } } } diff --git a/pkg/config/spec.go b/pkg/config/spec.go index 917eae6..7e023ed 100644 --- a/pkg/config/spec.go +++ b/pkg/config/spec.go @@ -47,15 +47,22 @@ const ( TiB ) -// TODO: Move it to the sdk -func resolveTarget(fs v1.FS, target string) (string, error) { +// resolveTarget will try to resovle a /dev/disk/by-X disk into the final real disk under /dev/X +// We use it to calculate the device on the fly for the Config and the InstallSpec but we leave +// the original value in teh config.Collector so its written down in the final cloud config in the +// installed system, so users can know what parameters it was installed with in case they need to refer +// to it down the line to know what was the original parametes +// If the target is a normal /dev/X we dont do anything and return the original value so normal installs +// should not be affected +func resolveTarget(target string) (string, error) { // Accept that the target can be a /dev/disk/by-{label,uuid,path,etc..} and resolve it into a /dev/device if strings.HasPrefix(target, "/dev/disk/by-") { // we dont accept partitions as target so check and fail earlier for those that are partuuid or parlabel if strings.Contains(target, "partlabel") || strings.Contains(target, "partuuid") { return "", fmt.Errorf("target contains 'parlabel' or 'partuuid', looks like its a partition instead of a disk: %s", target) } - device, err := fs.Readlink(target) + // Use EvanSymlinks to properly resolve the full path to the target + device, err := filepath.EvalSymlinks(target) if err != nil { return "", fmt.Errorf("failed to read device link for %s: %w", target, err) } @@ -64,7 +71,7 @@ func resolveTarget(fs v1.FS, target string) (string, error) { } return device, nil } - // If we dont resolve and dont fail, just return the original target + // If we don't resolve and don't fail, just return the original target return target, nil } @@ -88,7 +95,8 @@ func NewInstallSpec(cfg *Config) (*v1.InstallSpec, error) { firmware = v1.BIOS } - dev, err := resolveTarget(cfg.Fs, cfg.Install.Device) + // Resolve the install target + dev, err := resolveTarget(cfg.Install.Device) if err != nil { return nil, err } @@ -164,6 +172,12 @@ func NewInstallSpec(cfg *Config) (*v1.InstallSpec, error) { return nil, fmt.Errorf("failed unmarshalling the full spec: %w", err) } + // resolve also the target of the spec so we can partition properly + spec.Target, err = resolveTarget(spec.Target) + if err != nil { + return nil, err + } + // Calculate the partitions afterwards so they use the image sizes for the final partition sizes spec.Partitions = NewInstallElementalPartitions(cfg.Logger, spec) @@ -354,11 +368,11 @@ func NewUpgradeSpec(cfg *Config) (*v1.UpgradeSpec, error) { // Deep look to see if upgrade.recovery == true in the config // if yes, we set the upgrade spec "Entry" to "recovery" entry := "" - _, ok := cfg.Config["upgrade"] + _, ok := cfg.Config.Values["upgrade"] if ok { - _, ok = cfg.Config["upgrade"].(collector.Config)["recovery"] + _, ok = cfg.Config.Values["upgrade"].(collector.ConfigValues)["recovery"] if ok { - if cfg.Config["upgrade"].(collector.Config)["recovery"].(bool) { + if cfg.Config.Values["upgrade"].(collector.ConfigValues)["recovery"].(bool) { entry = constants.BootEntryRecovery } } @@ -433,7 +447,6 @@ func NewResetSpec(cfg *Config) (*v1.ResetSpec, error) { return nil, fmt.Errorf("could not read host partitions") } ep := v1.NewElementalPartitionsFromList(parts) - if efiExists { if ep.EFI == nil { return nil, fmt.Errorf("EFI partition not found") @@ -466,7 +479,6 @@ func NewResetSpec(cfg *Config) (*v1.ResetSpec, error) { target := ep.State.Disk // OEM partition is not a hard requirement for reset unless we have the reset oem flag - cfg.Logger.Info(litter.Sdump(ep.OEM)) if ep.OEM == nil { // We could have oem in lvm which won't appear in ghw list ep.OEM = partitions.GetPartitionViaDM(cfg.Fs, constants.OEMLabel) diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index cbf9395..66b3762 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -18,9 +18,10 @@ package constants import ( "errors" - "github.com/gofrs/uuid" "os" "strings" + + "github.com/gofrs/uuid" ) const ( @@ -168,14 +169,25 @@ func GetGrubModules() []string { return []string{"loopback.mod", "squash4.mod", "xzio.mod", "gzio.mod", "regexp.mod"} } -func GetConfigScanDirs() []string { +// GetYipConfigDirs returns all the directories where "yip" configuration might +// live. These include the directories were we store our system overlay files: +// https://github.com/kairos-io/packages/tree/main/packages/static/kairos-overlay-files/files/system/oem +func GetYipConfigDirs() []string { + return append(GetUserConfigDirs(), "/system/oem") +} + +// GetUserConfigDirs returns all the directories that might have configuration +// supplied by the user. They are in an order which allows the users to override +// baked-in configuration (e.g. in livecd, under /run/initramfs/live) with +// configuration coming from datasource (e.g. a datasource cdrom, written under /oem). +// That's why writable paths are last. +func GetUserConfigDirs() []string { return []string{ - "/oem", - "/system/oem", - "/usr/local/cloud-config", "/run/initramfs/live", "/etc/kairos", // Default system configuration file https://github.com/kairos-io/kairos/issues/2221 "/etc/elemental", // for backwards compatibility + "/usr/local/cloud-config", + "/oem", } } diff --git a/pkg/elemental/elemental.go b/pkg/elemental/elemental.go index d37c309..27b47ff 100644 --- a/pkg/elemental/elemental.go +++ b/pkg/elemental/elemental.go @@ -103,7 +103,7 @@ func (e *Elemental) PartitionAndFormatDevice(i v1.SharedInstallSpec) error { e.config.Logger.Errorf("Udevadm settle failed: %s", err) } // Partitions are in order so we can format them via that - for index, p := range table.GetPartitions() { + for _, p := range table.GetPartitions() { for _, configPart := range i.GetPartitions().PartitionsByInstallOrder(i.GetExtraPartitions()) { if configPart.Name == cnst.BiosPartName { // Grub partition on non-EFI is not formatted. Grub is directly installed on it @@ -112,7 +112,16 @@ func (e *Elemental) PartitionAndFormatDevice(i v1.SharedInstallSpec) error { // we have to match the Fs it was asked with the partition in the system if p.(*gpt.Partition).Name == configPart.Name { e.config.Logger.Debugf("Formatting partition: %s", configPart.FilesystemLabel) - err = partitioner.FormatDevice(e.config.Runner, fmt.Sprintf("%s%d", i.GetTarget(), index+1), configPart.FS, configPart.FilesystemLabel) + // Get full partition path by the /dev/disk/by-partlabel/ facility + // So we don't need to infer the actual device under it but get udev to tell us + // So this works for "normal" devices that have the "expected" partitions (i.e. /dev/sda has /dev/sda1, /dev/sda2) + // And "weird" devices that have special subdevices like mmc or nvme + // i.e. /dev/mmcblk0 has /dev/mmcblk0p1, /dev/mmcblk0p2 + device, err := filepath.EvalSymlinks(fmt.Sprintf("/dev/disk/by-partlabel/%s", configPart.Name)) + if err != nil { + e.config.Logger.Errorf("Failed finding partition %s by partition label: %s", configPart.FilesystemLabel, err) + } + err = partitioner.FormatDevice(e.config.Runner, device, configPart.FS, configPart.FilesystemLabel) if err != nil { e.config.Logger.Errorf("Failed formatting partition: %s", err) return err @@ -341,9 +350,9 @@ func (e *Elemental) DeployImage(img *v1.Image, leaveMounted bool) (info interfac } } } else if img.Label != "" && img.FS != cnst.SquashFs { - _, err = e.config.Runner.Run("tune2fs", "-L", img.Label, img.File) + out, err := e.config.Runner.Run("tune2fs", "-L", img.Label, img.File) if err != nil { - e.config.Logger.Errorf("Failed to apply label %s to %s", img.Label, img.File) + e.config.Logger.Errorf("Failed to apply label %s to %s: %s", img.Label, img.File, string(out)) _ = e.config.Fs.Remove(img.File) return nil, err } @@ -538,13 +547,16 @@ func (e Elemental) UpdateSourcesFormDownloadedISO(workDir string, activeImg *v1. return nil } -// SetDefaultGrubEntry Sets the default_meny_entry value in Config.GrubOEMEnv file at in -// State partition mountpoint. If there is not a custom value in the os-release file, we do nothing +// SetDefaultGrubEntry Sets the default_menu_entry value in Config.GrubOEMEnv file at in +// State partition mountpoint. If there is not a custom value in the kairos-release file, we do nothing // As the grub config already has a sane default func (e Elemental) SetDefaultGrubEntry(partMountPoint string, imgMountPoint string, defaultEntry string) error { if defaultEntry == "" { - osRelease, err := utils.LoadEnvFile(e.config.Fs, filepath.Join(imgMountPoint, "etc", "os-release")) + var osRelease map[string]string + osRelease, err := utils.LoadEnvFile(e.config.Fs, filepath.Join(imgMountPoint, "etc", "kairos-release")) if err != nil { + // Fallback to os-release + osRelease, err = utils.LoadEnvFile(e.config.Fs, filepath.Join(imgMountPoint, "etc", "os-release")) e.config.Logger.Warnf("Could not load os-release file: %v", err) return nil } diff --git a/pkg/elemental/elemental_test.go b/pkg/elemental/elemental_test.go index dc76485..05d5b9c 100644 --- a/pkg/elemental/elemental_test.go +++ b/pkg/elemental/elemental_test.go @@ -849,7 +849,7 @@ var _ = Describe("Elemental", Label("elemental"), func() { Expect(err).To(BeNil()) Expect(varsParsed["default_menu_entry"]).To(Equal("dio")) }) - It("does nothing on empty default entry and no /etc/os-release", func() { + It("does nothing on empty default entry and no /etc/kairos-release", func() { el := elemental.NewElemental(config) Expect(config.Fs.Mkdir("/mountpoint", cnst.DirPerm)).To(BeNil()) Expect(el.SetDefaultGrubEntry("/mountpoint", "/imgMountPoint", "")).To(BeNil()) @@ -859,10 +859,10 @@ var _ = Describe("Elemental", Label("elemental"), func() { _, err = config.Fs.Stat(filepath.Join("/tmp", cnst.GrubOEMEnv)) Expect(err).ToNot(BeNil()) }) - It("loads /etc/os-release on empty default entry", func() { + It("loads /etc/kairos-release on empty default entry", func() { err := fsutils.MkdirAll(config.Fs, "/imgMountPoint/etc", cnst.DirPerm) Expect(err).ShouldNot(HaveOccurred()) - err = config.Fs.WriteFile("/imgMountPoint/etc/os-release", []byte("GRUB_ENTRY_NAME=test"), cnst.FilePerm) + err = config.Fs.WriteFile("/imgMountPoint/etc/kairos-release", []byte("GRUB_ENTRY_NAME=test"), cnst.FilePerm) Expect(err).ShouldNot(HaveOccurred()) Expect(config.Fs.Mkdir("/mountpoint", cnst.DirPerm)).To(BeNil()) diff --git a/pkg/utils/common.go b/pkg/utils/common.go index abc11b5..e7a26d9 100644 --- a/pkg/utils/common.go +++ b/pkg/utils/common.go @@ -83,6 +83,7 @@ func CopyFile(fs v1.FS, source string, target string) (err error) { // Source files are concatenated into target file in the given order. // If target is a directory source is copied into that directory using // 1st source name file. +// TODO: Log errors, return errors, whatever but dont ignore them func ConcatFiles(fs v1.FS, sources []string, target string) (err error) { if len(sources) == 0 { return fmt.Errorf("Empty sources list") diff --git a/pkg/utils/grub.go b/pkg/utils/grub.go index 470b2d5..cb08ecb 100644 --- a/pkg/utils/grub.go +++ b/pkg/utils/grub.go @@ -172,9 +172,25 @@ func (g Grub) Install(target, rootDir, bootDir, grubConf, tty string, efi bool, return err } - flavor, err := utils.OSRelease("FLAVOR", filepath.Join(cnst.ActiveDir, "etc/os-release")) + flavor, err := utils.OSRelease("FLAVOR", filepath.Join(cnst.ActiveDir, "etc/kairos-release")) if err != nil { - g.config.Logger.Warnf("Failed reading os-release from %s: %v", filepath.Join(cnst.ActiveDir, "etc/os-release"), err) + // Fallback to os-release + flavor, err = utils.OSRelease("FLAVOR", filepath.Join(cnst.ActiveDir, "os/kairos-release")) + if err != nil { + g.config.Logger.Warnf("Failed reading release info from %s and %s: %v", filepath.Join(cnst.ActiveDir, "etc/kairos-release"), filepath.Join(cnst.ActiveDir, "os/kairos-release"), err) + } + } + if flavor == "" { + // If os-release is gone with our vars, we dont know what flavor are we in, we should know if we are on ubuntu as we need + // a workaround for the grub efi install + // So lets try to get the info from the normal keys shipped with the os + flavorFromId, err := utils.OSRelease("ID", filepath.Join(cnst.ActiveDir, "etc/os-release")) + if err != nil { + g.config.Logger.Logger.Err(err).Msg("Getting flavor") + } + if strings.Contains(strings.ToLower(flavorFromId), "ubuntu") { + flavor = "ubuntu" + } } g.config.Logger.Debugf("Detected Flavor: %s", flavor) // Copy needed files for efi boot @@ -188,7 +204,15 @@ func (g Grub) Install(target, rootDir, bootDir, grubConf, tty string, efi bool, // providing a generic package // Shim is not available in Alpine + rpi - model, err := utils.OSRelease("KAIROS_MODEL", filepath.Join(cnst.ActiveDir, "etc/os-release")) + var model string + model, err = utils.OSRelease("KAIROS_MODEL", filepath.Join(cnst.ActiveDir, "etc/kairos-release")) + if err != nil { + // Fallback into os-release + model, err = utils.OSRelease("KAIROS_MODEL", filepath.Join(cnst.ActiveDir, "etc/os-release")) + if err != nil { + g.config.Logger.Warnf("Failed reading model info from %s and %s: %v", filepath.Join(cnst.ActiveDir, "etc/kairos-release"), filepath.Join(cnst.ActiveDir, "os/kairos-release"), err) + } + } if strings.Contains(strings.ToLower(flavor), "alpine") && strings.Contains(strings.ToLower(model), "rpi") { g.config.Logger.Debug("Running on Alpine+RPI, not copying shim or grub.") } else { @@ -210,7 +234,7 @@ func (g Grub) Install(target, rootDir, bootDir, grubConf, tty string, efi bool, } // Ubuntu efi searches for the grub.cfg file under /EFI/ubuntu/grub.cfg while we store it under /boot/grub2/grub.cfg // workaround this by copying it there as well - // read the os-release from the rootfs to know if we are creating a ubuntu based iso + // read the kairos-release from the rootfs to know if we are creating a ubuntu based iso if strings.Contains(strings.ToLower(flavor), "ubuntu") { g.config.Logger.Infof("Ubuntu based ISO detected, copying grub.cfg to /EFI/ubuntu/grub.cfg") err = fsutils.MkdirAll(g.config.Fs, filepath.Join(cnst.EfiDir, "EFI/ubuntu/"), constants.DirPerm)