Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/codeql-verification.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ jobs:
set -euo pipefail
test -z "$(git status --porcelain)"
git merge-base --is-ancestor c8663d12dd253ef13258750dca056d4b1219fc10 HEAD
grep -Fq 'VERSION_OVERRIDE: v0.13.25' .github/workflows/validate.yml
grep -Fq 'VERSION_OVERRIDE: v0.13.26' .github/workflows/validate.yml
grep -Fq 'SHA256SUMS' scripts/package
grep -Fq 'bash scripts/verify-package "$linux_asset"' .github/workflows/validate.yml
grep -Fq 'bash scripts/verify-package dist/artifacts/node-agent-0.13.25.tar.gz' .github/workflows/security-release-gate.yml
grep -Fq 'bash scripts/verify-package dist/artifacts/node-agent-0.13.26.tar.gz' .github/workflows/security-release-gate.yml

- name: Install the release Go toolchain
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
Expand All @@ -68,7 +68,7 @@ jobs:
export GOFLAGS=-mod=vendor
mkdir -p "$GITHUB_WORKSPACE/bin"
CGO_ENABLED=0 go build -trimpath -tags 'netgo osusergo' \
-ldflags='-w -s -X main.VERSION=v0.13.25' \
-ldflags='-w -s -X main.VERSION=v0.13.26' \
-o "$GITHUB_WORKSPACE/bin/node-agent" ./

- name: Analyze without publishing temporary alerts
Expand Down
22 changes: 11 additions & 11 deletions .github/workflows/security-release-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ jobs:
timeout-minutes: 120
env:
DAPPER_IMAGE: pasturestack/node-agent-dapper:${{ github.sha }}
RUNTIME_IMAGE: pasturestack/node-agent:v0.13.25
RUNTIME_IMAGE: pasturestack/node-agent:v0.13.26
TRIVY_IMAGE: aquasec/trivy:0.74.0@sha256:62b1e65e8869bc4b4c6aa4fa2b21595256c7c2f6018a9d9ad61caf87187c1969
VERSION_OVERRIDE: v0.13.25
VERSION_OVERRIDE: v0.13.26
steps:
- name: Check out candidate
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand Down Expand Up @@ -50,20 +50,20 @@ jobs:
set -euo pipefail
CROSS=1 VERSION_OVERRIDE="$VERSION_OVERRIDE" make DAPPER_IMAGE="$DAPPER_IMAGE" ci
make DAPPER_IMAGE="$DAPPER_IMAGE" IMAGE_NAME=pasturestack/node-agent \
TAG=v0.13.25 VERSION_OVERRIDE="$VERSION_OVERRIDE" package-image
test -s dist/artifacts/node-agent-0.13.25.tar.gz
test -s dist/artifacts/node-agent-0.13.25-windows-amd64.zip
TAG=v0.13.26 VERSION_OVERRIDE="$VERSION_OVERRIDE" package-image
test -s dist/artifacts/node-agent-0.13.26.tar.gz
test -s dist/artifacts/node-agent-0.13.26-windows-amd64.zip
test "$(cat dist/image)" = "$RUNTIME_IMAGE"
gzip -t dist/artifacts/node-agent-0.13.25.tar.gz
bash scripts/verify-package dist/artifacts/node-agent-0.13.25.tar.gz
unzip -t dist/artifacts/node-agent-0.13.25-windows-amd64.zip
sha256sum dist/artifacts/node-agent-0.13.25.tar.gz \
dist/artifacts/node-agent-0.13.25-windows-amd64.zip \
gzip -t dist/artifacts/node-agent-0.13.26.tar.gz
bash scripts/verify-package dist/artifacts/node-agent-0.13.26.tar.gz
unzip -t dist/artifacts/node-agent-0.13.26-windows-amd64.zip
sha256sum dist/artifacts/node-agent-0.13.26.tar.gz \
dist/artifacts/node-agent-0.13.26-windows-amd64.zip \
bin/node-agent > evidence/product-artifacts.sha256
docker image inspect "$RUNTIME_IMAGE" > evidence/runtime-image-inspect.json
docker run --rm --entrypoint /usr/bin/node-agent "$RUNTIME_IMAGE" --version \
> evidence/runtime-version.txt
grep -Fxq 'node-agent version v0.13.25' evidence/runtime-version.txt
grep -Fxq 'node-agent version v0.13.26' evidence/runtime-version.txt

- name: Verify reproducible Linux binary
shell: bash
Expand Down
16 changes: 8 additions & 8 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ jobs:
id: package
env:
CROSS: "1"
VERSION_OVERRIDE: v0.13.25
VERSION_OVERRIDE: v0.13.26
run: |
set -euo pipefail
make ci
linux_asset="dist/artifacts/node-agent-0.13.25.tar.gz"
windows_asset="dist/artifacts/node-agent-0.13.25-windows-amd64.zip"
linux_asset="dist/artifacts/node-agent-0.13.26.tar.gz"
windows_asset="dist/artifacts/node-agent-0.13.26-windows-amd64.zip"
test -s "$linux_asset"
test -s "$windows_asset"
gzip -t "$linux_asset"
Expand All @@ -48,19 +48,19 @@ jobs:
(
cd dist/artifacts
sha256sum \
node-agent-0.13.25.tar.gz \
node-agent-0.13.25-windows-amd64.zip >SHA256SUMS
node-agent-0.13.26.tar.gz \
node-agent-0.13.26-windows-amd64.zip >SHA256SUMS
)
printf 'NODE_AGENT_VALIDATION_OK source=%s version=%s artifacts=linux,windows\n' \
"$GITHUB_SHA" "$VERSION_OVERRIDE"

- name: Retain reviewed release candidate
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: node-agent-0.13.25
name: node-agent-0.13.26
path: |
dist/artifacts/node-agent-0.13.25.tar.gz
dist/artifacts/node-agent-0.13.25-windows-amd64.zip
dist/artifacts/node-agent-0.13.26.tar.gz
dist/artifacts/node-agent-0.13.26-windows-amd64.zip
dist/artifacts/SHA256SUMS
if-no-files-found: error
retention-days: 30
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ client 0.5, gopsutil v4.26, mapstructure v2.5, netlink v1.3, and netns v0.0.5.
The retired AWS SDK v1, Aliyungo, root Docker module, GOPATH/Godeps, and Trash
dependency paths are not part of the build.

For the reviewed `0.13.25` compatibility release, `VERSION_OVERRIDE=v0.13.25 CROSS=1 make package` produces the deterministic flat assets `node-agent-0.13.25.tar.gz` and `node-agent-0.13.25-windows-amd64.zip`. The Linux archive carries both the legacy SHA-1 manifests and the current SHA-256 manifests required by the host installer. PastureStack Server serves both assets from its matching GitHub Release and verifies their outer SHA-256 entries before use; operators do not need an artifact mirror. The Windows ZIP uses the neutral `pasturestack/` include layout. A replacement Windows bootstrap image and upgrade/rollback tests are still required before Windows hosts are supported.
For the reviewed `0.13.26` compatibility release, `VERSION_OVERRIDE=v0.13.26 CROSS=1 make package` produces the deterministic flat assets `node-agent-0.13.26.tar.gz` and `node-agent-0.13.26-windows-amd64.zip`. The Linux archive carries both the legacy SHA-1 manifests and the current SHA-256 manifests required by the host installer. PastureStack Server serves both assets from its matching GitHub Release and verifies their outer SHA-256 entries before use; operators do not need an artifact mirror. The Windows ZIP uses the neutral `pasturestack/` include layout. A replacement Windows bootstrap image and upgrade/rollback tests are still required before Windows hosts are supported.

The `host.port.check` event performs a read-only host-port preflight through the existing agent event channel. It reports Docker bindings from running and stopped containers and, on Linux, listening TCP/UDP sockets visible through the existing host `/proc` mount. Incomplete host socket inspection is reported as unknown; it is never presented as an available port.

Expand Down
10 changes: 10 additions & 0 deletions docs/releases/node-agent-0.13.26.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Node Agent v0.13.26

This release restores event handling against current Docker inspect payloads.

- Decode current typed Docker network addresses, hardware addresses, and port
sets without rejecting the control-plane event representation.
- Preserve existing event models and API fields while accepting empty Docker
set values.
- Cover the exact network and exposed-port payload that previously left a
reconnected host online but unable to finish workload reconciliation.
32 changes: 29 additions & 3 deletions utilities/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"os"
"os/exec"
"path/filepath"
"reflect"
"regexp"
"strconv"
"strings"
Expand All @@ -32,22 +33,47 @@ func GetInstanceAndHost(event *revents.Event) (model.Instance, model.Host, error

data := event.Data
var ihm model.InstanceHostMap
if err := mapstructure.Decode(data["instanceHostMap"], &ihm); err != nil {
if err := decodeEventModel(data["instanceHostMap"], &ihm); err != nil {
return model.Instance{}, model.Host{}, errors.Wrap(err, constants.GetInstanceAndHostError+"failed to marshall instancehostmap")
}

var instance model.Instance
if err := mapstructure.Decode(ihm.Instance, &instance); err != nil {
if err := decodeEventModel(ihm.Instance, &instance); err != nil {
return model.Instance{}, model.Host{}, errors.Wrap(err, constants.GetInstanceAndHostError+"failed to marshall instance data")
}
var host model.Host
if err := mapstructure.Decode(ihm.Host, &host); err != nil {
if err := decodeEventModel(ihm.Host, &host); err != nil {
return model.Instance{}, model.Host{}, errors.Wrap(err, constants.GetInstanceAndHostError+"failed to marshall host data")
}

return instance, host, nil
}

var emptyStructType = reflect.TypeOf(struct{}{})

func decodeEventModel(input interface{}, output interface{}) error {
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
Result: output,
TagName: "json",
WeaklyTypedInput: true,
DecodeHook: mapstructure.ComposeDecodeHookFunc(
func(from reflect.Type, to reflect.Type, value interface{}) (interface{}, error) {
if to == emptyStructType {
if text, ok := value.(string); ok && text == "" {
return struct{}{}, nil
}
}
return value, nil
},
mapstructure.TextUnmarshallerHookFunc(),
),
})
if err != nil {
return err
}
return decoder.Decode(input)
}

func IsNoOp(data model.ProcessData) bool {
return data.ContainerNoOpEvent
}
Expand Down
47 changes: 47 additions & 0 deletions utilities/utils/utils_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package utils

import (
"net/netip"
"testing"

"github.com/PastureStack/node-agent/internal/dockerapi/types"
"github.com/moby/moby/api/types/network"
revents "github.com/rancher/event-subscriber/events"
)

func TestIsNodeAgentContainer(t *testing.T) {
Expand Down Expand Up @@ -48,3 +51,47 @@ func TestIsNodeAgentContainer(t *testing.T) {
})
}
}

func TestGetInstanceAndHostDecodesCurrentDockerInspectTypes(t *testing.T) {
event := &revents.Event{Data: map[string]interface{}{
"instanceHostMap": map[string]interface{}{
"instance": map[string]interface{}{
"id": 17,
"data": map[string]interface{}{
"dockerInspect": map[string]interface{}{
"Config": map[string]interface{}{
"ExposedPorts": map[string]interface{}{"8080/tcp": ""},
},
"NetworkSettings": map[string]interface{}{
"Networks": map[string]interface{}{
"bridge": map[string]interface{}{
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"MacAddress": "02:42:ac:11:00:02",
"IPv6Gateway": "",
"GlobalIPv6Address": "",
},
},
},
},
},
},
"host": map[string]interface{}{"id": 10, "state": "active"},
},
}}

instance, host, err := GetInstanceAndHost(event)
if err != nil {
t.Fatalf("GetInstanceAndHost() error = %v", err)
}
if instance.ID != 17 || host.ID != 10 || host.State != "active" {
t.Fatalf("decoded identities = instance %d, host %d/%q", instance.ID, host.ID, host.State)
}
endpoint := instance.Data.DockerInspect.NetworkSettings.Networks["bridge"]
if endpoint == nil || endpoint.IPAddress != netip.MustParseAddr("172.17.0.2") || endpoint.MacAddress.String() != "02:42:ac:11:00:02" {
t.Fatalf("decoded endpoint = %#v", endpoint)
}
if _, ok := instance.Data.DockerInspect.Config.ExposedPorts[network.MustParsePort("8080/tcp")]; !ok {
t.Fatal("empty Docker port-set value was not decoded")
}
}
Loading