Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9db31cf
Updated and aligned platforms docs
uk-bolly Sep 8, 2026
88d3295
fix(mount): report unsupported platforms honestly, without touching t…
uk-bolly Sep 8, 2026
5ca14f0
fix(process): fail when every status read fails, not just when one does
uk-bolly Sep 8, 2026
9adacfe
fix(paths): resolve absolute Windows includes and backslash home paths
uk-bolly Sep 8, 2026
dd647cf
fix(autoadd): report a resource skipped because its lookup failed
uk-bolly Sep 8, 2026
011c10e
docs(changelog): FEAT-013 Windows correctness cluster
uk-bolly Sep 8, 2026
fa0bed5
test(windows): assert the mount fix end to end, and forbid the silent…
uk-bolly Sep 8, 2026
87b5efa
fix(autoadd): honour --log-level, as every other subcommand does
uk-bolly Sep 9, 2026
083f2ab
test(process): pin the n=1 boundary the all-or-nothing rule cannot ex…
uk-bolly Sep 9, 2026
e6b179c
docs: correct four false statements found in review
uk-bolly Sep 9, 2026
7154335
docs(platforms): record the Windows port and process findings as meas…
uk-bolly Sep 9, 2026
5462665
docs(releases): name both signing keys and say which signs what
uk-bolly Sep 9, 2026
2ec07fd
Updated windows data
uk-bolly Sep 9, 2026
17a3568
fix(windows): kill the whole process tree when a command times out
uk-bolly Sep 9, 2026
9cb5bce
test(windows): prove a grandchild dies on timeout and survives success
uk-bolly Sep 9, 2026
63a574a
feat(registry): accept regedit and PowerShell hive spellings, add view:
uk-bolly Sep 9, 2026
9947cd9
test(registry): pin the grammar, the views, and the value-vs-key warning
uk-bolly Sep 9, 2026
76b72b4
test(windows): assert the new registry grammar and record the new totals
uk-bolly Sep 9, 2026
3bca090
docs: view:, the trailing-backslash rule, and Windows process trees
uk-bolly Sep 9, 2026
242905a
Updated ready for 0.12.0 release
uk-bolly Sep 10, 2026
129cfcf
Updated file
uk-bolly Sep 10, 2026
3df9949
fix(windows): make the Job Object attach flag atomic
uk-bolly Sep 10, 2026
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
115 changes: 114 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,54 @@
# Changelog

## 0.11.3 based on krameff/goss v0.6.0 - container package description
## 0.12.0 based on krameff/goss v0.6.0 - Windows registry grammar and process trees

- windows registry
- hive names accept the spellings Windows tools actually print. `regedit`'s
address bar shows `HKEY_LOCAL_MACHINE\...` and `Get-ItemProperty` shows
`HKLM:\...`; both, and the long forms with the PowerShell colon, now parse
alongside the short names, case-insensitively. Previously a path copied out
of either tool had to be hand-edited before syver would take it
- **new attribute `view:`** -- `32`, `64` or `native`, selecting the WOW64
registry view a check reads. On 64-bit Windows some keys exist twice, and a
spec had no way to say which copy it meant: it got whichever syver's own
architecture saw. `native` is the default and behaves exactly as every
existing gossfile did, which a test pins rather than assumes
- `type:` reports the **full** `REG_*` set. `REG_NONE`, `REG_LINK`,
`REG_DWORD_BIG_ENDIAN` and the three `REG_RESOURCE_*` hardware descriptor
types previously came back as `UNKNOWN(n)`, so a type assertion against
them could not be written. `REG_DWORD_BIG_ENDIAN` is deliberately not read
as an integer: doing so would return a confidently wrong number in the
wrong byte order, so it renders as hex like the other opaque types
- a value lookup that misses while a **key of that name exists in the same
place** now says so. This is the one shape where a truthful answer reliably
answers a different question from the one asked: `HKLM\...\ProfileList`
asks about a value and is false, `HKLM\...\ProfileList\` asks about the
key and is true. Asserting `exists: false` against the first therefore
PASSES while testing nothing the author intended. The trailing backslash is
still not guessed at or made optional -- guessing moves the ambiguity
somewhere you cannot see it -- but the confusable case is no longer silent
- `REG_EXPAND_SZ` is documented as compared **unexpanded**: a value holding
`%SystemRoot%\System32` is matched as that literal text. Unchanged
behaviour, previously unstated

- windows command timeouts
- a `command:` that timed out killed the process syver started and left
anything that process had spawned running. `command:` runs through
`cmd /c`, so the thing syver starts is a shell and the thing that hangs is
the shell's child -- meaning the leak was the normal case on Windows, not
an edge one. The process now runs inside a **Job Object** whose closure
terminates the whole tree
- this makes Windows **stronger** than Linux and macOS here, which is worth
stating because the documentation said the opposite. A process that calls
`setsid` leaves the POSIX process group and is permanently out of reach; a
process cannot leave a job unless it was created to break away and the job
permits it. The daemonising case that escapes on POSIX does not escape on
Windows
- a command that **succeeds** is untouched. Only a timeout terminates the
tree, so a check that deliberately starts a background process and exits
zero still leaves it running
- the Windows PowerShell probe path used by `service:` had no process-group
protection at all, and now shares the same mechanism

- container image
- the package page for the published image showed **no description**. The
Expand All @@ -13,6 +61,14 @@
what a registry can read about them without pulling one

- docs
- the Windows support matrix now records what was **measured** rather than
what was assumed. `port:` errors with `not implemented yet` on Windows:
gopsutil ships a Windows backend for connection enumeration, so the row had
recorded an assumption nobody had checked. `process: status` reads *not
implemented* rather than *broken*, because that is what the library reports.
`process: user` **works**, and had read *no data*. The page says where each
came from, and notes that the `port:` and `mount:` fixtures are skipped, so
a green Windows suite does not cover them
- three documentation pages existed but were unreachable from the
documentation index: **goss vs Syver**, **Windows** and **Testing**. They
are now listed. Navigation on the published site was unaffected, since it is
Expand Down Expand Up @@ -64,6 +120,63 @@
assertions driven from Linux and 19 on a real Windows host, and it is why a
resource quietly disappearing shows up as a rise in skips rather than a
failure
- the command support matrix in `docs/platforms.md` understated macOS and
Windows. It marked `serve` on Windows as never tried, and `serve` and
`validate` on macOS as working but without automated tests. All three run on
every push and pass, as do `add` and `help` on both platforms. The cells are
now measured from CI job logs rather than estimated, and the page says which
log lines prove them, because the workflow derives its target from `go env`
and so tells you a lane is wired up rather than that it ran. `autoadd` and
`render` are unchanged: `autoadd`'s fixture is skipped on both platforms and
`render` has no fixture anywhere


- windows
- a `mount:` check on Windows said the **mountpoint was not found**, blaming
the path the operator wrote for what is actually a missing implementation.
It now says it is not supported on this platform. This is Windows-only:
`mount:` is already fully supported on macOS, through the same POSIX lookup
Linux uses, so neither platform's behaviour changes. The fix is a platform
capability check placed before the shared lookup rather than a reordering
of it, so supported platforms take exactly the path they did
- `process: status` returned an **empty list and no error** on Windows, where
the underlying library cannot read process state at all. The check ran,
found the process, reported nothing about it and passed. It now errors when
every matching process fails to read, while still tolerating a process that
exits between being listed and being read when others were read
successfully. **Note the boundary:** where exactly one process matches,
which is the common case for a single-instance daemon, those two are the
same event and the check errors rather than tolerating it. That is the
intended trade: an error naming the cause is better than an empty result
reported as success for a process that demonstrably exists.
`process: user` had the same shape and gets the same rule
- `syver add mount` on Windows now **fails** instead of silently writing an
`exists: false` entry it never verified. It is the same fix seen from the
`add` side: the old mountpoint-not-found error was excluded from
propagation as an ordinary "not a mount" answer, and the honest
not-supported error is not
- a gossfile include written as an absolute Windows path (`C:\...`) was
resolved relative to the including file instead, because the absoluteness
test was a literal check for a leading `/`. Paths beginning `/` still behave
exactly as before on every platform. **A UNC path (`\\server\share\...`)
now resolves too**, where it was previously joined onto the including file's
directory and silently failed to resolve. That follows from using the
platform's own definition of absolute, and makes a gossfile on a Windows
file share usable as a shared include
- `~\Documents\x` did not expand on Windows. Home-directory expansion split
the path on `/` only, so the whole string was read as an account name

- autoadd
- `syver autoadd` now honours `--log-level` / `SYVER_LOGLEVEL`, and its
output carries the same timestamped format as every other subcommand. It
was the one verb that never installed the level filter, which did not matter
while nothing in that path logged. The warning below made it matter
- `syver autoadd` **silently skipped** any resource whose existence check
failed, making an unreadable resource indistinguishable from one that is
genuinely absent. It now reports the reason and carries on, rather than
either hiding it or aborting the whole run over one entry. Lookups that ran
and found nothing, such as a path that is not a mount or a service that is
not registered, stay quiet: those are answers, not failures

## 0.11.2 based on krameff/goss v0.6.0 - signed SBOMs and a patched base image

Expand Down
68 changes: 67 additions & 1 deletion RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,29 @@ are this project's own, cut after the fork.
Releases are assembled on `devel` and merged to `main` at release time, so from
0.9.1 onward a release carries several branches rather than one.

Every tag from v0.7.0 onward is annotated and GPG-signed with the same key.
Every tag from v0.7.0 onward is annotated and GPG-signed.

**Two different keys sign two different things, and confusing them makes a good
signature look like a bad one.**

| What | Signed by | Key |
| --- | --- | --- |
| Git tags | the maintainer's own key | `5154CE6E4F8712D87B9C870DCC071079D4E84F77` |
| Release artifacts: `SHA256SUMS`, the SBOMs | the project signing key, published as [`krameff-syver-key.asc`](krameff-syver-key.asc) | `CD218D529C95DC65A71F18D84C9E5095CABE5092` |

So importing `krameff-syver-key.asc` and then running `git verify-tag` will
report that it has no public key for the signature. That is expected, not a
problem with the tag. Verify each with the key that signed it:

```sh
git verify-tag v0.11.2 # maintainer key
gpg --verify syver_0.11.2_SHA256SUMS.sig \
syver_0.11.2_SHA256SUMS # project key
```

This line previously read "signed with the same key", which had no antecedent
and invited exactly that mistake.

"Released" is the date the tag object was created, which is not always the
commit date: v0.7.0 was committed on 2026-08-18 and tagged on 2026-08-20.
v0.6.0 has no tag in this repository and uses the date its changelog entry
Expand All @@ -37,6 +59,8 @@ artifacts and signatures always correspond to the tag as it now stands.

## Contents

* [v0.12.0 - Windows registry grammar and process trees](#v0120---windows-registry-grammar-and-process-trees)
-- **assembled, not released**
* [v0.11.2 - Signed SBOMs and a patched base image](#v0112---signed-sboms-and-a-patched-base-image)
* [v0.11.1 - Documentation site corrections](#v0111---documentation-site-corrections)
* [v0.11.0 - Windows: stop returning confident wrong answers](#v0110---windows-stop-returning-confident-wrong-answers)
Expand All @@ -53,6 +77,48 @@ artifacts and signatures always correspond to the tag as it now stands.

---

## v0.12.0 - Windows registry grammar and process trees

**NOT RELEASED. Assembled on two feature branches, neither merged, nothing
tagged.** This entry exists so the work is traceable before it ships; replace
the pending fields at tag time rather than writing them now.

| Field | Value |
| --- | --- |
| Released | pending |
| Tag | pending |
| Commit | pending |
| Base | krameff/goss v0.6.0 |
| Integration branch | `feature/windows-depth-wave2` (FEAT-013) and `feature/windows-registry-and-job-objects` (FEAT-012, FEAT-017), the second branched from the first. Both still need a PR; pushes do not build feature branches, so neither has been through CI |
| Scope | measure at tag time: `git diff --stat devel..feature/windows-registry-and-job-objects` |
| Changelog | [0.12.0](CHANGELOG.md#0120-based-on-krameffgoss-v060---windows-registry-grammar-and-process-trees) |

**Why this is a minor and not a patch.** `registry:` gains a `view:` attribute.
The resource layer is deliberately cross-platform, so a new attribute appears in
`docs/schema.yaml` on every platform, not just the one that honours it. That is
user-facing spec syntax and cannot ship under a patch.

It also carries the container-package-description work that had been assembled
on `devel` under an unreleased `0.11.3` heading. That heading no longer exists;
the work rides here.

**Validation, stated because it is unusually good for Windows work and unusually
uneven.** FEAT-012 and FEAT-017 were exercised on two independent Windows images
-- a Windows Server 2025 guest and a Windows 11 Enterprise host -- with the unit
tests passing on both and the registry fixture producing an identical
`Count: 20, Failed: 0, Skipped: 3`. The `view:` attribute was proven to read
genuinely different data by creating one key through each WOW64 view with
different values and reading both back through the shipped binary.
FEAT-013 was the gap in this record and it is now closed: on 2026-09-10 its
tests were run explicitly on Windows 11 from a binary built at `3bca090` and all
passed, including `TestMountReportsUnsupportedNotNotFound` (the mount fix
itself), `TestProcessNeverReportsNothingSuccessfully`, the four
`TestCollectPerProcess` cases and the `RealPath` set. Two mount tests skip by
design, being POSIX-only. All three of FEAT-012, FEAT-013 and FEAT-017 have now
been exercised on a real Windows host.

---

## v0.11.2 - Signed SBOMs and a patched base image

| Field | Value |
Expand Down
11 changes: 11 additions & 0 deletions add.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,17 @@ func AddResource(fileName string, syverConfig SyverConfig, resourceName, key str
// AutoAddResources is a simple wrapper to add multiple resources
func AutoAddResources(fileName string, keys []string, c *util.Config) error {
var err error
// autoadd was the one subcommand that never installed the level filter.
// AddResources, validate and serve all call this; autoadd did not, and it
// did not matter while nothing here logged. FEAT-013 added a [WARN] for a
// resource skipped because its lookup failed, which made it matter: without
// this, `syver -L ERROR autoadd ...` could not silence that line, and it
// printed in Go's raw default format rather than the RFC3339 one every
// other [WARN] in this codebase uses.
err = setLogLevel(c)
if err != nil {
return err
}
outStoreFormat, err = getStoreFormatFromFileName(fileName)
if err != nil {
return err
Expand Down
Loading