Repository navigation
Releases: magicdrive/kjak
Release list
v1.2.2
What's Changed
- build: pin Hephaestus v1.5.0 by @magicdrive in #49
- ci(mutation): drop the weekly run by @magicdrive in #50
Full Changelog: v1.2.1...v1.2.2
v1.2.1
What's Changed
- chore(renovate): raise the Node.js major of renovate-check from the dashboard by @magicdrive in #48
Full Changelog: v1.2.0...v1.2.1
v1.2.0
kjak v1.2.0
kjak sends one notification to Slack, Discord, e-mail, any HTTP API or a
plugin of your own, from the command line, a script or CI. v1.2.0 lets a
plugin installed with Homebrew run on macOS, under a statement of its
content that you make. It is a minor release: everything v1.0.0 guarantees
(docs/stability.md)
is kept.
Highlights
-
Plugins installed by Homebrew (macOS). Homebrew makes
<prefix>/bin,Cellarandoptwritable by theadmingroup, so kjak
refused every plugin installed withbrew. Such a plugin now runs when
its SHA-256 is the one you stated: a feather of your configuration whose
sha256equals the file's, or a project whosekjak config trust
recorded that path and SHA-256.kjak feather pluginsshows the value to
pin:[feathers.mac] type = "external" plugin = "notify-macos" sha256 = "..." # from kjak feather plugins; update it after brew upgrade
kjak does not treat the
admingroup as root (writing there needs no
authentication). The exception covers only the group-write rule, only
bin,Cellarandoptof/opt/homebrewand/usr/local(owned by
you, groupadmin, not writable by others, ACLs checked as before), and
only a file in a keg named for the plugin that is a Mach-O executable
whose load commands name system libraries alone (not a script, not a
program linked to a library of Homebrew; what the plugin opens or starts
at run time is not checked). The content and the place are checked again before
every run, and once more just before the process starts. What it opens to
other admin users, and the short window that remains before the exec, are
in docs/security.md.
Compatibility
- Nothing that ran before is refused now, and nothing is removed or changed
in meaning. A plugin anywhere but Homebrew's directories is checked
exactly as in v1.1.0. - New: in
kjak feather plugins -o json,plugins[].homebrew(true for a
plugin in Homebrew's directories, with itssha256); in the text output,
its stateHomebrew: runs only for a feather with sha256 = "..." (or a project trust).kjak config trustnotes such a plugin. - Linux (Linuxbrew included) and Windows behave as in v1.1.0.
- The plugin protocol is still version 1.
Install
brew install magicdrive/tap/kjak # macOS, Linux; brew upgrade kjak lateror, without Homebrew, on macOS and Linux:
curl -fsSLO https://raw.githubusercontent.com/magicdrive/kjak/v1.2.0/install.sh
sh install.sh --version v1.2.0 # into ~/.local/bin; sh install.sh --upgrade lateror the archive of your platform below, checked with kjak_checksums.txt
and, optionally, its build provenance:
gh attestation verify kjak_1.2.0_linux_amd64.tar.gz --repo magicdrive/kjak \
--signer-workflow magicdrive/kjak/.github/workflows/release.yml --source-ref refs/tags/v1.2.0Developers can build from source with Go 1.27 (make build, or
go install github.com/magicdrive/kjak@v1.2.0).
Platforms
| platform | archive |
|---|---|
| macOS arm64, amd64 | tar.gz; Homebrew, install script |
| Linux amd64, arm64 | tar.gz; Homebrew, install script |
| Windows amd64 | zip |
The notes of v1.0.0 on keychains, secrets-file permissions and plugins per
platform still apply.
Known limitations
- A plugin installed by Homebrew needs its
sha256updated after each
brew upgrade. Between kjak's last check and the exec, another admin user
of the Mac could still replace it (docs/security.md). - OS-native notifications are not supported.
- Windows has no keychain support. On macOS and Linux the keychain tools
are tested as test doubles, not against a real keychain. - Changes other than adding a feather, group or template rewrite the
configuration file without its comments. - Plugins are not sandboxed: they run with your rights.
- The macOS binaries are not notarized.
Full Changelog: v1.1.0...v1.2.0
v1.1.0
kjak v1.1.0
kjak sends one notification to Slack, Discord, e-mail, any HTTP API or a
plugin of your own, from the command line, a script or CI. v1.1.0 is about
getting started: a tutorial for every feather in English and Japanese,
complete configuration examples, a self-documenting kjak config init, and
configuration changes that keep your comments when they only add. It is a
minor release: everything v1.0.0 guarantees
(docs/stability.md)
is kept.
Highlights
- Tutorials for every feather, in English and Japanese: Discord, Slack,
Gmail, any SMTP server, HTTP APIs and plugins, from the setup on the
service to a first notification, with completeconfig.tomlfiles, the
command line, secrets, troubleshooting and security notes
(docs/tutorials).
The plugin tutorial comes with a small working plugin,
kjak-feather-log. - Configuration examples: complete files for one feather, several,
groups, templates and secrets files
(docs/examples). kjak config initwrites a catalog: the same configuration as before
(no feather), followed by a commented example of every feather, group,
template and default, each feather linked to its tutorial.kjak config init --minimalwrites it without the examples.- Comments kept when adding.
feather add,group setandtemplate setof a new name append to the file and keep its comments and layout.
Other changes still rewrite it, and now say so when that drops comments
(kjak: note: FILE was rewritten without its comments). - Documentation checked in CI. The example files and the TOML blocks of
the tutorials, the getting started guides and the READMEs are parsed and
validated (the TOML of the other documents is parsed). Thekjak
commands of the documents'shblocks are run, in order, against the
real command line in an empty sandbox (sendas a dry run): an unknown
command, flag, level, type or a value of the wrong form fails the build;
lines with shell substitutions or redirections, and commands that read
standard input, are left out. Links are checked, and a feather type
without a tutorial in both languages, or without an example, fails the
build.
Compatibility
- New: the flag
kjak config init --minimal. Nothing is removed or
changed in meaning. kjak config initwrites a longer file; its configuration is the same as
v1.0.0's (tested). The text of the file is not part of the contract.- A file that only gets a new feather, group or template is appended to
instead of rewritten; what it contains reads back exactly as a rewrite
would (kjak checks, and rewrites otherwise). - OS-native notifications are still not supported: the type names
os,
native,macos,linuxandwindowsstay reserved and refused.
Install
brew install magicdrive/tap/kjak # macOS, Linux; brew upgrade kjak lateror, without Homebrew, on macOS and Linux:
curl -fsSLO https://raw.githubusercontent.com/magicdrive/kjak/v1.1.0/install.sh
sh install.sh --version v1.1.0 # into ~/.local/bin; sh install.sh --upgrade lateror the archive of your platform below, checked with kjak_checksums.txt
and, optionally, its build provenance:
gh attestation verify kjak_1.1.0_linux_amd64.tar.gz --repo magicdrive/kjak \
--signer-workflow magicdrive/kjak/.github/workflows/release.yml --source-ref refs/tags/v1.1.0Developers can build from source with Go 1.27 (make build, or
go install github.com/magicdrive/kjak@v1.1.0).
Platforms
| platform | archive |
|---|---|
| macOS arm64, amd64 | tar.gz; Homebrew, install script |
| Linux amd64, arm64 | tar.gz; Homebrew, install script |
| Windows amd64 | zip |
The notes of v1.0.0 on keychains, secrets-file permissions and plugins per
platform still apply.
Known limitations
- OS-native notifications are not supported (a later version).
- Windows has no keychain support. On macOS and Linux the keychain tools
are tested as test doubles, not against a real keychain. - Changes other than adding a feather, group or template rewrite the
configuration file without its comments. - Plugins are not sandboxed: they run with your rights.
- The macOS binaries are not notarized.
Full Changelog: v1.0.0...v1.1.0
v1.0.0
kjak v1.0.0
kjak sends one notification to Slack, Discord, e-mail, any HTTP API or a
plugin of your own, from the command line, a script or CI. v1.0.0 is the
first stable release: the command line, the configuration, the JSON output,
the exit status, the error codes and the plugin protocol are now a contract
kept for all of 1.x (docs/stability.md).
Highlights
- Stable contract. docs/stability.md lists what 1.x
guarantees (commands and flags, exit status, JSON schema version 1, error
codes, configuration and secrets files, the trust store, retry semantics,
plugin protocol v1, the version line), what it does not (text output,
messages, provider payloads, descriptive values inside JSON documents),
and what makes a major, a minor or a patch release. Tests check it against
the code. - Secrets files. Secrets live in a private TOML file of their own
({ secret = "dev_slack.webhook_url" }), personal (--secrets,
$KJAK_SECRETS,~/.config/kjak/secrets.toml) or per project
(.kjak.secrets.toml, trusted with the project). kjak refuses a secrets
file anyone else can read, checking the mode bits and the ACLs on Linux,
macOS and Windows.kjak config migrate-secretsmoves literal secrets out
of a configuration file. httpfeathers. Any HTTP API: method, headers, query, bearer/basic/
header authentication by reference, a JSON or text body or a template,
success statuses, idempotency keys and method-aware retries, behind an
address policy (https only, no redirects, no loopback, private,
link-local or cloud-metadata address unless allowed; checked where the
connection is made).- External feather plugins.
kjak-feather-<name>executables speaking
a documented JSON protocol (v1) on stdin/stdout. kjak checks which
executable runs, gives it only its own secrets and a minimal environment
in a private working directory, and ends its whole process tree (process
group on Unix, Job Object on Windows) at its timeout, the deadline and
Ctrl-C, SIGTERM or SIGHUP.kjak feather pluginslists them without
running any. - Project trust, tightened. A trusted
.kjak.tomlreads your
environment variables, keychain entries and personal secrets only by the
names you allowed when you trusted it, and its slack, discord and email
feathers reach public addresses only unless the file allows more. - Install script.
install.shinstalls a release on macOS and Linux
(amd64, arm64) without Homebrew: checked against the release's checksums,
only the binary taken out of the archive, the installed one replaced in a
single rename, nosudo, noPATHchange. - Quality. golangci-lint, fuzzing, mutation testing, end-to-end tests of
the built binary (and of v0.0.4 configurations), native CI on every
release platform.
Senders
| feather | sends | secrets | retries |
|---|---|---|---|
slack |
an incoming webhook message | webhook_url |
429, 5xx except 502/504, a connection that failed before the request was sent |
discord |
a webhook message (title, body, level color, URL) | webhook_url |
as slack, retry_after honored |
email |
an e-mail over SMTP (STARTTLS, TLS or, explicitly, plain), AUTH PLAIN/LOGIN |
password |
SMTP 4xx, a connection that failed before the data |
http |
any HTTP request; the body is JSON, text or a template of the message | url_secret, auth |
by method (retry.policy): GET/PUT/DELETE, and POST/PATCH with an idempotency key |
external |
whatever the plugin does | the ones it is given | only with retry.policy = "plugin" |
Groups send to several feathers at once; templates turn variables into a
message (--template, --template-file, kjak template render). Every
target is delivered on its own, at most --concurrency at a time, within
one deadline (--timeout, default 10s): one feather's failure never hides
another's result. The report (-o json) gives each target's status,
acceptance (confirmed, rejected, unknown), attempts and errors, and the
outcome of the send (success, partial, failure, canceled); exit 0
when nothing failed, 1 when a delivery failed, 2 when nothing was sent
(usage, configuration, credentials, trust), 130 when interrupted. An
unknown acceptance (a request that may have been delivered) is never
retried.
Breaking changes
Compared to v0.0.4. Each is a security fix or a fix of the output contract,
refused before anything is sent; the migration guide has the steps.
- Project feathers need a new trust for
envandkeychain
references. A project trusted by v0.0.4 stays trusted, but its slack,
discord and email feathers that read an environment variable or a
keychain entry are refused (exit 2, nothing sent) until you trust the
project again and allow those names (kjak config trust; in CI
--yes --allow-user-secrets:--yesalone now fails for such a project). - A project's slack, discord and email feathers reach public addresses
only, without a proxy. A project feather that sends tolocalhost, a
private network or a private SMTP server fails withblocked(exit 1)
until the project allows it (allow_networks,allow_hosts). Global
feathers are not affected. --tomust name something.--to ""or--to ,(an empty variable
in a script) is a usage error (exit 2); v0.0.4 sent todefaults.targets.- Message templates cannot loop (
range,define,template,
block), andprintfrefuses a width or precision of 1000 or more,*
and argument indexes. - Configuration files must be regular files. A configuration file, a
project file or the trust store that is a FIFO, a device or a directory is
refused (a symbolic link to a regular file still works). - Text fields cannot hold control characters (
username,host,
user,from,subject_prefix,plugin,path, ..., a keychain
serviceoraccount), and a keychainaccountcannot hold/. config validate -o jsonprints a JSON document on success
("valid": true, the files, the literal secrets by key); v0.0.4 printed
thePATH: OKtext lines there. Failures print the same error document as
before, and the exit status is unchanged.kjak versionandkjak feather typestake no argument but
--help(an unexpected one is exit 2).- Downgrade: once a trust entry uses the new keys (a project secrets
file, allowed names, plugins), v0.0.4 cannot read the trust store
("broken trust store"). Keep a copy oftrust.tomlif you may go back.
Unchanged: configurations without literals or control characters, env
and keychain references of the global configuration, groups, templates
without loops, the JSON report (fields were only added), the exit status,
the request bodies sent to Slack, Discord and e-mail.
Deprecated
{ literal = "..." }credentials andfeather add --secret-stdin. They
keep working in 1.x;kjak sendwarns about them on stderr (and warns
that the file is readable by others when it is),kjak config validate
reports them and--strictrefuses them. Move them with
kjak config migrate-secrets, then rotate them.
Migration
- Install v1.0.0 (below).
kjak config validate(and--strictto find literals);
kjak config migrate-secretsif you have any, then rotate the secrets
that were ever committed or shared.- In each repository with a
.kjak.toml: review it, then
kjak config trustagain if a send says the trust does not allow a
reference; addallow_networks/allow_hoststo project feathers that
send to a local or private address. In CI use
kjak config trust --yes --allow-user-secretsafter the review. - Replace
range/define/template/blockin message templates; check
scripts that pass--to "$VAR".
Details: docs/migration.md.
Security
- Secrets: separate private files, checked on the opened file (owner, mode,
ACLs; fail closed), never printed. Every error and report is redacted of
every resolved secret — also its URL forms, the base64 forms sent for HTTP
basic authentication and SMTPAUTH, a fragment left by a truncation and
multi-line secrets. A configuration file with literal secrets that others
can read is warned about. - Projects: every
env/keychain/personal secret reference and plugin
environment variable is allowed by name; an address policy for every
network feather of a project; plugins pinned by the trust (path and
SHA-256). - Plugins: a minimal environment (
PATHwith absolute directories only), a
private working directory per attempt, the whole process tree ended; a
plugin file is found only under its exact name (also on file systems that
ignore case). - Untrusted text: terminal escape sequences in a project file are refused
or escaped before they reach your terminal (config trustshows what you
approve). - SSRF: metadata services (AWS, GCP, Azure WireServer, Tencent, ...),
IPv4-in-IPv6 and NAT64 forms are refused; DNS rebinding is covered by
checking the address where the connection is made. - Denial of service: a FIFO as a configuration file and looping templates
are refused; an SMTP server that does not answerQUITdoes not hold the
send. - TLS: kjak uses the system's certificate authorities;
SSL_CERT_FILEand
SSL_CERT_DIRreplace them on macOS and Windows (Go 1.27), see
docs/security.md.
Report a vulnerability privately: SECURITY.md.
Fixes
results[].duration_msin the JSON re...
v0.0.4
What's Changed
- Revert "build: adopt Hephaestus and modernize development workflows" (pushed to main by mistake) by @magicdrive in #12
- build: adopt Hephaestus and modernize development workflows by @magicdrive in #13
Full Changelog: v0.0.3...v0.0.4
v0.0.3
Changelog
- 72b511f Merge pull request #11 from magicdrive/fix/e2e-inherited-descriptors-limit
- 271389a test(e2e): give kjak the raised descriptor limit with its 1100 descriptors
- 2a05859 Merge pull request #10 from magicdrive/fix/macos-ci-after-pr9
- be062e2 test(subcmd): wait for the writers a test leaves, before the next counts descriptors
- 9d5468e Merge pull request #9 from magicdrive/hardening/production-validation
- f78144c docs: align the delivery tables with the classification
- 1f713dc test: protocol matrices of Slack, Discord and SMTP through the engine
- 3202044 fix(discord): cap the retry_after of a 429 body like Retry-After
- e97272f fix(send): see a macOS FIFO writer that closes without writing
- 0a646c2 Merge pull request #8 from magicdrive/hardening/deadline-io-contract
- 010f2d4 docs: a FIFO is read through kjak's descriptor; macOS constraints
- c822676 fix(send): cancel a macOS FIFO read without writing into the FIFO
- 82ffead test: fail rather than skip the high-descriptor tests on CI
- c7ef75c docs(troubleshooting): standard input macOS cannot wait for
- ccea166 fix(send): keep input cancelable at any descriptor number
- dcab135 docs: describe the deadline of a send, FIFO input and the output contract
- bc6ccb1 fix(cli): tell a closed pipe on Windows too
- d9fc8b1 test(cli): pin the output contract and the broken pipe on every system
- 2b96706 fix(send): make standard input and a --json-input FIFO cancelable
- 236930d fix(send): start the deadline before the credentials
- add1e37 Merge pull request #7 from magicdrive/hardening/production-reliability
- bd0b273 docs: describe SIGTERM, interrupted stdin and unwritable output
- 20c0450 fix(cli): fail a command whose output cannot be written
- 16765c5 fix(credential): do not wait for the output of a keychain tool's children
- 5858b18 fix(send): stop reading standard input when interrupted
- f409466 fix(cmd): cancel on SIGTERM and survive a closed stdout
- 6fc6f6a Merge pull request #6 from magicdrive/refactor/transport-libraries
- d83905f fix(email): do not fold a subject into a line of only white space
- 844d991 docs(development): record why the transports keep the standard library
- e6a0058 fix(email): fold long To and Subject headers
- 8a54872 Merge pull request #5 from magicdrive/docs/bilingual-setup-guide
- 70fc218 test(e2e): check the commands of the guides, not only README.md
- 7f5b159 docs: add bilingual setup and configuration guides
v0.0.2
Changelog
- 8037ece fix(release): release with PERSONAL_GITHUB_TOKEN, as in ark and enma
- 7bc2ca6 Merge pull request #4 from magicdrive/refactor/align-ark-enma
- 07db5e6 build(make): follow enma's Makefile
- 7adccd4 build(release): let GoReleaser publish, as in ark and enma
- 41177be docs: describe the simplified CI and release
- 31f2a7b ci: align CI with enma (test, lint, fuzz, dist)
- 01bdd6b Merge pull request #3 from magicdrive/fix/release-immutable-verification
- 6be5105 docs(release): record the v0.0.1 failure and re-run rules
- af45c89 fix(release): wait for the immutable, attested release and keep the tap layout
kjak v0.0.1
kjak v0.0.1. Install: brew install magicdrive/tap/kjak. Verify: gh attestation verify --repo magicdrive/kjak