Repository navigation
v0.4.0
Added
-
Each release now includes a Windows on Arm build,
hodeishield-<version>-aarch64-pc-windows-msvc.zip.
It is built natively on a Windows on Arm runner, itshodeishield.exeis signed with Authenticode
like the x64 one and checked to need no Visual C++ runtime, and the archive is listed in
SHA256SUMS, signed with Sigstore, covered by the build provenance and has its own SBOM. The
Scoop manifest offers it to Windows on Arm; the MSI and winget package remain x64 only. CI now
runs the tests, clippy and the import check on Windows on Arm too.
(#37) -
On an interactive terminal, the CLI now tells you in one line on standard error when a newer
release exists. It asks GitHub's public releases API (no credential or identifier is sent) at most
once a day, stays silent with--json,--csv,completions, when standard error is not a
terminal and whenCIis set, and never changes a command's output or exit code. Turn it off with
HODEISHIELD_NO_UPDATE_CHECK=1orhodeishield config set update_check false; the README's
"New-version notice" section lists exactly what is sent.
(#38) -
A container image,
ghcr.io/hodeitek/hodeishield-cli, forlinux/amd64andlinux/arm64, built
for each stable release: the release's own binary on a distroless base, running as a non-root
user, tagged with the exact version only. It is signed by digest with Sigstore and carries the
release's SBOM as a signed attestation. (#36) -
Several client tenants with one portfolio key.
hodeishield tenants listlists the client
tenants the key may read. The key is created by an organisation administrator of an active MSSP
organisation and goes inHODEISHIELD_API_KEY. The global--tenant <slug|id>selects one client
for any read command, includinggetandcompliance posture, and prints the line
Client tenant: <slug> (<id>)on standard error.--all-tenantsreads every client on alistcommand and adds
tenant_id,tenant_slugandtenant_nameto each row in--jsonand--csv(aTENANT
column in the table). An unknown client fails with exit code 5, before any data is read. Without
these options nothing changes.--all-tenantsasks one client at a time and skips clients that
are inactive or whose licence is not in force, with a note on standard error; the command still
exits 0 when only inactive clients are skipped. A client whose licence status the CLI does not
know is not read and is named on standard error. A client that fails when it is read because its
licence is not in force (exit code 8) or it is not found (exit code 5) is also named and skipped.
In both cases the other clients' data is printed and the command then exits non-zero (with the
code of the first client that failed, or 1 for an unknown licence status), so a script never takes
a partial result for a complete one. Any other failure stops the run before anything is printed,
for example exit code 6 (naming the limit) when a rate limit is exhausted. Against an API without
portfolio access the commands fail with exit code 7. The README has a new "Several tenants (MSSP)"
section. (#54,
#45)
Changed (scripting surface)
- In a session where the system keychain cannot be reached (a Windows SSH or other network logon,
or a Secret Service on Linux that is locked or does not answer) and no API key is set, commands
such aswhoamino longer fail with a raw platform error and exit code 1. They now say that the
system keychain is not available in this session, suggestHODEISHIELD_API_KEYfor remote and
automated sessions, and exit with 3, the code for "not authenticated". With the key set, nothing
changes. What to do: treat exit 3 as "this session cannot keep a login, use an API key", and do
not rely on exit 1 for this case. (#111) - A failed command no longer exits 0 when the API's error message happens to contain the words
"Broken pipe". The CLI now treats a failure as a closed output pipe (hodeishield ... | head -1,
which still exits 0 silently) only when writing to standard output fails with that I/O error,
never because of the text of a message. What to do: a script that relied on exit 0 after such a
failed command must now handle the documented non-zero code (see "Exit codes" in the README).
(#105) - A broken pipe from anything other than standard output (a network connection, a file, the
configuration being saved) no longer ends a command with exit code 0 and no message. Only a write
to standard output that fails because the reader went away is treated as a closed pipe; any other
broken pipe is reported as an error with a non-zero exit code. What to do: as above, handle the
non-zero code instead of expecting exit 0. (#105)
Changed
- The README documents more of how to use and depend on the CLI: the interface stability policy,
with what a script can rely on (#58, #92); using the CLI behind a proxy or
TLS inspection (#25, #89); the beta programme and its terms
(#52, #90); defining a profile before signing in to it, and waiting for
msiexecin a silent install (#87).
SECURITY.mdnow says what happens after a vulnerability report, where a notice about an affected
release appears (the README has an empty place for it), and how advisories are published, from
a template kept indocs/(#120).
SECURITY.mdnow states the support period (from 1.0.0, five years of security fixes per major
version; until then, the latest 0.x release), anddocs/user-information.mdgathers the contact
details, secure use, updating, removal and where the SBOM is published
(#127,
#128). - The alerts
--severityfilter now shows in--helpthe values the API lists (critical,high,
medium,low,info), and warns on standard error about a value the API does not list or has
deprecated. For the deprecated values (critico,alto,medio,bajo, accepted until
2027-01-14) the warning names the value to use instead. The value is still sent as typed, and exit
codes do not change. The CLI now follows version 2026-10-16 of the API document.
(#53) - Errors that involve a client tenant now say so and what to do. An unknown client tenant (404
TENANT_NOT_FOUND) points tohodeishield tenants list; a portfolio key rejected for a missing
scope points to an organisation administrator; a rate limit names whether it is the key's, the
organisation's or the client tenant's own, and says whether other clients are affected; a
credential that covers several clients without--tenantor--all-tenantsis told to pick one;
and--tenantwith a credential for one tenant only is told to leave it out. Messages and
hints go to standard error; exit codes do not change. (#54,
#45)
Fixed
- Terminal output cleaning now also replaces the line and paragraph separators (U+2028, U+2029),
the deprecated format characters U+206A to U+206F and the tag characters and variation selectors supplement
(U+E0000 to U+E0FFF), which display differently from what they contain. This applies to tables,
detail views, CSV and the escaping of--jsonoutput. (#106) - CSV output now also defuses a field whose first character after any leading whitespace is
=,
+,-or@, or one of their full-width forms (for example" =1+1", or a no-break space
before=cmd). It decides on the text as it is written, because some spreadsheet applications
trim the whitespace before evaluating the cell. Numbers are still written as they are.
(#106) install.shnow looks up the latest release over HTTPS only, with TLS 1.2 or newer, as the
download already did, so a redirect cannot lead that lookup to another protocol.
(#106)hodeishield loginnow checks that the system keychain can keep a session before it opens the
browser or shows a device code, and stops there with the usual pointer to API keys. If saving the
session still fails after the app has issued tokens, the CLI revokes the refresh token and then
the access token, says so on standard error and exits non-zero, instead of leaving an active
grant that nothing holds. The hint for a missing keychain now names the one for your system
(Secret Service, the Keychain prompt, or Credential Manager). (#101)- A stalled or slow local connection can no longer keep the browser sign-in listener busy past its
timeout. Each connection now has a total time limit for its request, and no read waits beyond the
overall sign-in deadline, and the deadline is checked before every connection is accepted, so a
process sending a byte every few seconds, or connecting over and over, cannot block the real
redirect or stophodeishield loginfrom timing out. A client that resets its connection before
it is accepted no longer ends the sign-in. (#104)
Verify the download as described in Verifying releases.
For the signature check, cosign v3 is recommended; with cosign v2 (2.4 or newer), add --new-bundle-format to the cosign verify-blob commands.
install.sh needs cosign v3 to check the signature; cosign v2 support comes in 0.4.1.
What's Changed
- Describe the module design principles in CONTRIBUTING by Gorka Gonzalo (@d0ubl3g) in #85
- Report OpenAPI drift in an issue instead of a pull request by Gorka Gonzalo (@d0ubl3g) in #86
- Document defining a profile before signing in to it, and waiting for msiexec by Gorka Gonzalo (@d0ubl3g) in #87
- Document proxies and TLS inspection by Gorka Gonzalo (@d0ubl3g) in #89
- Link the beta programme and its terms from the README by Gorka Gonzalo (@d0ubl3g) in #90
- Expose the tenant the API answered for in the response metadata by Gorka Gonzalo (@d0ubl3g) in #91
- State the interface stability policy by Gorka Gonzalo (@d0ubl3g) in #92
- Read known filter values from the OpenAPI document by Gorka Gonzalo (@d0ubl3g) in #93
- Test the scripting surface: exit codes, JSON, CSV and output streams by Gorka Gonzalo (@d0ubl3g) in #94
- Warn when a filter value is not one the API lists by Gorka Gonzalo (@d0ubl3g) in #95
- Point legacy severity values to their new names by Gorka Gonzalo (@d0ubl3g) in #97
- Publish a signed multi-architecture container image with each release by Gorka Gonzalo (@d0ubl3g) in #98
- Test proxy and TLS inspection handling in CI by Gorka Gonzalo (@d0ubl3g) in #96
- Tell interactive users when a newer version is released by Gorka Gonzalo (@d0ubl3g) in #99
- Propose options for signing in without a keychain by Gorka Gonzalo (@d0ubl3g) in #100
- Refuse to sign in without a token store, and revoke tokens that cannot be kept by Gorka Gonzalo (@d0ubl3g) in #102
- Polish the messages when sign-in cannot store or revoke tokens by Gorka Gonzalo (@d0ubl3g) in #103
- Bound the sign-in listener per connection and decide a closed pipe on the error kind by Gorka Gonzalo (@d0ubl3g) in #107
- Update dependencies to their latest compatible releases by Gorka Gonzalo (@d0ubl3g) in #108
- Harden output sanitising, CSV defusing, the update notice and the installer lookup by Gorka Gonzalo (@d0ubl3g) in #109
- Link the C runtime statically on Windows and report an unreachable keychain as not authenticated by Gorka Gonzalo (@d0ubl3g) in #112
- Note when Unblock-File matters on Windows by Gorka Gonzalo (@d0ubl3g) in #115
- Treat only a closed standard output as a closed pipe by Gorka Gonzalo (@d0ubl3g) in #116
- Build, sign and test Windows on Arm by Gorka Gonzalo (@d0ubl3g) in #117
- List the exit code changes as scripting-surface changes by Gorka Gonzalo (@d0ubl3g) in #118
- Describe the disclosure process and where security notices appear by Gorka Gonzalo (@d0ubl3g) in #131
- State the support period and add a user information document by Gorka Gonzalo (@d0ubl3g) in #132
- Read several client tenants with one portfolio credential by Gorka Gonzalo (@d0ubl3g) in #134
- Say that a client tenant's own rate limits can be lower by Gorka Gonzalo (@d0ubl3g) in #137
- Follow version 2026-10-16 of the API document by Gorka Gonzalo (@d0ubl3g) in #138
- Prepare 0.4.0 by Gorka Gonzalo (@d0ubl3g) in #139
- Release 0.4.0 by Gorka Gonzalo (@d0ubl3g) in #140
Full Changelog: v0.3.1...v0.4.0