Commit graph

23772 commits

Author SHA1 Message Date
Allison Karlitskaya
9d0695647c ws: be more explicit when handling hostnames on cli
`cockpit-ws` has never protected hostnames from being interpreted as cli
options when passing them to the auth commands (`cockpit-session`,
`cockpit-ssh`, `cockpit.beiboot`).  There have been a couple of relevant
changes over the years:

  - our move to using cockpit-session via unix socket has removed
    exposure to this problem for `cockpit-session`

  - our move from `cockpit-ssh` (glib argument parser) to
    `cockpit.beiboot` (Python argparse) has unfortunately exposed us to
    https://github.com/python/cpython/issues/66623 which means (due to a
    strange heuristic) that arguments starting with '-' can be
    interpreted as positionals if they also have spaces in them

This gives a way to get a hostname starting with a `-` to ssh (where it
*will* be interpreted as an option) and the following argument (the
python invocation on the remote) will be interpreted as the hostname.
Fortunately, new versions of ssh will reject this hostname.  In any
case, we should firm up the code here and add `--` to ensure that it's
definitely interpreted as a hostname by ssh.

For a similar reason add a `--` to the ssh command in `cockpit-ws`.

CVE-2026-4631
2026-04-08 15:18:32 +02:00
Allison Karlitskaya
99deafc66f shell: fix forwarding of iframe "init" messages
The shell currently accidentally forwards the "init" message from each
iframe to the shell, meaning an extra init message gets sent for every
page.

Based on the comments in this function about "Only control messages with
a channel are forwardable" and "Everything else gets forwarded", it
seems unintentional that init messages (which are explicitly handled and
don't have a channel) were ever intended to be forwarded.

Unfortunately, the "does it have a channel?" check is an "else if" in
the same chain of conditions as the check for `command == "init"` and
(unlike all of the other commands that are checked for) the `"init"`
case doesn't have a `return;` statement at the bottom.

As a result, we accidentally fall through to the "Everything else gets
forwarded" case and send the init message from the iframe along to the
ws.

This bug dates all the way back to the original version of the shell
added in bf2f46943b ("shell: Implement new multiple dashboards
navigation").  It went unnoticed because the websocket handling code
doesn't check if an init message was already received.

Unfortunately, because the shell is served by the bridge, we need to
support old versions of the shell indefinitely.  In order to avoid
regressions, add a test to ensure that cockpit-ws will always accept
these extra init messages.
2026-04-08 14:34:58 +02:00
Allison Karlitskaya
19b028a386 qunit: port test-protocol to TypeScript
This is done as a separate commit to make it easier to review each half.
Otherwise there's too much churn in the previous patch for git to even
be able to follow the rename.
2026-04-08 14:34:58 +02:00
Allison Karlitskaya
e0fd4ff18d qunit: switch test-protocol to an async/await style
...as we have some of the others.
2026-04-08 14:34:58 +02:00
Allison Karlitskaya
b98ce72aa5 test: fix a SPDX header, add a Copyright 2026-04-08 14:34:58 +02:00
Allison Karlitskaya
e17aed4bef qunit: remove half-close from test-stream
`test-stream` has a pair of tests which connect to the webserver itself
and speak HTTP directly in order to test if the `stream` channel is
working with TCP connections.

Unfortunately, after they send the request, they send a `"done"` control
message.  This is Cockpit's half-close indicator and the channel
translates it to `shutdown(SHUT_WR)` which causes the webserver to read
EOF.

At that point, cockpit-ws will continue sending the response and then
close the connection.  This behaviour in response to a half-closed
connection is non-standard though.  The webserver may interpret
half-close to mean that the request is finished or it may interpret it
to mean that the client wishes to abort.  After being discussed for
years, the httpwg seemed to have decided that the standard says nothing
on this point and should continue to say nothing on this point, adding
the following text:

   Note that a TCP connection that is half-closed by the client does not
   delimit a request message, nor does it imply that the client is no longer
   interested in a response. In general, transport signals cannot be relied
   upon to signal edge cases, since HTTP/1.1 is independent of transport.

 - https://github.com/httpwg/http-core/issues/22
 - https://github.com/httpwg/http-core/pull/431

Hypercorn behaves the same way as the existing cockpit-ws code.  There
is an open issue to change the behaviour in uvicorn, but it doesn't seem
to be under active consideration:
 - https://github.com/Kludex/uvicorn/issues/1264

Since this test is not really interested in testing the exact edge-case
behaviour of our HTTP server implementation, let's just remove the
half-close to avoid the issue.
2026-04-08 14:34:31 +02:00
Allison Karlitskaya
fa5dc123a7 qunit: fix HTTP request line in test-stream
cockpit-ws tolerates `\n` line endings but most other frameworks are
stricter about this and the spec is quite clear: the line ending must be
`\r\n`.
2026-04-08 14:34:31 +02:00
Allison Karlitskaya
03ac3b16e8 qunit: port test-stream to TypeScript 2026-04-08 14:34:31 +02:00
Allison Karlitskaya
c30f668332 qunit: switch test-stream to an async style
...and use the new Channel class at the same time.

Also: replace the character-by-character encoding with `TextEncoder` to
match the `TextDecoder` already in use on the receiving side.
2026-04-08 14:34:31 +02:00
GitHub Workflow
bb35d095e9 po: Update from Fedora Weblate
Closes #23103
2026-04-08 11:06:05 +02:00
Freya Gustavsson
5c802993b5 nav: Fix mobile spacing for System button
At some point we either changed the System button to a different
component or PatternFly started using a different CSS variable. Fixing
this is simple as we can also zero the button gap for the CSS grid.

Signed-off-by: Freya Gustavsson <freya@venefilyn.se>
2026-04-07 09:28:09 +03:00
dependabot[bot]
0623bfd700 Bump the esbuild group with 2 updates
Bumps the esbuild group with 2 updates: [esbuild](https://github.com/evanw/esbuild) and [esbuild-wasm](https://github.com/evanw/esbuild).

Updates `esbuild` from 0.27.4 to 0.28.0
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.27.4...v0.28.0)

Updates `esbuild-wasm` from 0.27.4 to 0.28.0
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.27.4...v0.28.0)

---
updated-dependencies:
- dependency-name: esbuild
  dependency-version: 0.28.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: esbuild
- dependency-name: esbuild-wasm
  dependency-version: 0.28.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: esbuild
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-05 20:26:38 +02:00
Allison Karlitskaya
4688f407b9 test_browser: don't skip test-dbus-address
This has been skipped since this file existed and was copied at that
point from the `pyTESTS_HANGING` list in the old automake test setup,
but even going back to that commit, it seems to be working.  It's
possible that something with libraries changed or that it was even
already working at that time, but in any case, it's working now.  Let's
run it and make sure it keeps working.

The only failing test is now the websocket test.  Move the single
exception into the body of the function and add a message about why.
2026-04-02 14:03:46 +02:00
Allison Karlitskaya
9321c9bbaf qunit "framed" tests: fix channel seed for iframe
Our "framed" tests create an iframe and implement a yolo version of the
router in the shell inside of a single function for forwarding messages
back and forth between the websocket and the iframe.  The instruct the
iframe to use a hardcoded `channel-seed` (ie: the prefix used on all
channel names) of `"2:"`.  That's not OK because the webserver told *us*
(the parent window) to use a particular channel seed and now we're just
making things up, which means that the channels created in the iframe
won't start with the channel seed that all messages on the websocket are
supposed to use.

This hasn't been a problem so far because nothing in the existing
`cockpit-ws` ever actually enforces the restriction that a particular
websocket only communicates using its own `channel-seed`.  The incoming
Python webserver is more strict about this point, however, which would
cause these tests to fail.

Let's derive the `channel-seed` for the iframe in a similar way to how
the shell does it.
2026-04-02 14:03:46 +02:00
Allison Karlitskaya
7c7944e237 mocksessionsocket: accept a Path
It's a bit of a stdlib quirk that `socket.bind()` doesn't accept a
`Path` even when many other calls like `os.unlink()` do.  Paper it over
so our own callers don't have to deal with it.
2026-04-02 14:03:46 +02:00
Allison Karlitskaya
1e753fb07b test/pytest/ws/: various very minor tweaks
Removing the hardcoded package name lets us move the files in this
directory around and use them with different names.  It's also just more
consistent with everything else in the directory.

Also fix a formatting issue that was introduced on a previous rebase.

Turn this into a proper package by adding an empty `__init__.py`.
2026-04-02 14:03:46 +02:00
Allison Karlitskaya
378a480edd test_browser: stop using yarl
A plain string is fine here if we know that it'll always have a trailing
`/` on it.
2026-04-02 14:03:46 +02:00
Allison Karlitskaya
0259d5c68d test-server: fix testing url output
When run from the tests, `test-server` outputs its URL to stdout without
the trailing slash.  That currently works because `yarl.URL()` picks up
the slack and adds it implicitly, but it's technically wrong and we want
to slowly move away from yarl.  Add the `/`..
2026-04-02 14:03:46 +02:00
Allison Karlitskaya
c4b1d2a7f9 cockpit-client: drop keep_fds=[3] to cockpit-ws
We used to create and bind the webserver listener socket for ourselves
in order to know what port number we'd get, and pass it into cockpit-ws
via the `LISTENER_FDS` mechanism.

We removed the dynamic port number in 6d6ad3602f ("c-client: Keep
localstorage") which cleared the way for the simplification of moving
the socket creation back to cockpit-ws in 8d32150aa7 ("client:
Simplify cockpit-ws startup").

Unfortunately the "simplify" commit forgot to remove the bit that
actually passed the fd, so since then we've been passing a random fd
through to beiboot.  Let's clean that up.
2026-04-02 14:03:46 +02:00
Freya Gustavsson
658f5d1ce4
test: Wait for memory to disappear (#23034)
Flaky pixel tests can occur where memory still shows on a disabled
service. Waiting on the memory to disappear before taking pixel tests
will ensure pixel tests match.

Fixes: https://github.com/cockpit-project/cockpit/issues/23030

Signed-off-by: Freya Gustavsson <freya@venefilyn.se>
2026-04-01 12:47:50 +02:00
GitHub Workflow
b0b35a7c3c po: Update from Fedora Weblate
Closes #23080
2026-04-01 08:46:07 +02:00
Allison Karlitskaya
a30c5d16d9 pytest/authorize: simplify nonce handling
Having this as a separate function is completely ridiculous in Python,
so let's get rid of it.  It's used from a single place (which
base64-encodes it) so we can just use the base64 version of the API from
the start.

Note also: 128 *bytes* is complete overkill here, so let's use 128bits
(16 bytes) instead.

Drop two extremely trivial testcases.
2026-03-31 13:52:05 +02:00
Allison Karlitskaya
e71b83b351 test/pytest: add a mock "session" socket server
This emulates the effect of `cockpit-session` being run as a template
unit by systemd with an associated `Accept=true` socket.  It has support
for basic authentication and 2FA and can be used as a library in an
async task.

We implement this using the authorize helpers we added in the last
commit.
2026-03-31 13:52:05 +02:00
Allison Karlitskaya
3515dd8523 test/pytest: add Python port of cockpitauthorize helpers
Port `src/common/cockpitauthorize.c` to Python as literally as
reasonably possible.  Copy all of the test cases as well.

We put this new code in the `test/pytest/ws/` subdirectory so that we
can have different ruff configuration: this code is meant to run with
Python 3.12+ and uses `ruff format` with the default options.

We write this code to be compatible with Python 3.12 (since we'll never
use it from the bridge and never send it via beiboot).  Make sure we
don't try to load it when running our older Python versions via tox.  We
can do that via an ignore list in conftest.py but need to adjust our
existing ignore hook so that the two can work together.

Assisted-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-31 13:52:05 +02:00
Allison Karlitskaya
4701f22b06 bridge: check for 'init' before channel messages
If you start talking to the bridge by immediately opening a channel
you'll get a confusing assertion failure deep down from the guts of the
bridge in the HostRoutingRule wondering why the `init_host` hasn't been
set yet on the `Router`.

Check this explicitly: `init` needs to happen before any channel control
or data messages.
2026-03-31 13:52:05 +02:00
Allison Karlitskaya
792b9a39f2 pkg/lib: fix qunit template
The `<%= title %>` business in the tests has gone unexpanded forever.
Change it to `%title%` which is what the plugin actually expands, and
change the plugin to expand more than once instance of the metavariables
it encounters (since the `%title%` is in the `<title>` and `<h1>` both).
2026-03-31 13:52:05 +02:00
Allison Karlitskaya
d163c4ee61 pyproject: add "test.pytest" to "known first party"
Otherwise when we do our incremental checks in the commit hook, ruff
doesn't see the file and assumes it's a system import.
2026-03-31 13:52:05 +02:00
Allison Karlitskaya
658f498a94 test/pytest: increase a time tolerance in pcp tests
10ms is pretty small and I just hit it with my laptop under load.
Increase it to 1s.
2026-03-31 13:52:05 +02:00
Jelle van der Waa
2ba4dac251 ws: support loading a custom login page
Anaconda wants to allow users to remotely log in Cockpit's WebUI
using a PIN for authentication. Instead of adding an Anaconda mode to
`cockpit.conf` allow Anaconda to bring its own login.html, JavaScript
and CSS. This gives Anaconda full flexibility over the login process
combined with implementing their own handler for basic auth.
2026-03-30 15:57:33 +02:00
dependabot[bot]
c7b8ad0aa7 Bump stylelint from 17.5.0 to 17.6.0 in the stylelint group
Bumps the stylelint group with 1 update: [stylelint](https://github.com/stylelint/stylelint).

Updates `stylelint` from 17.5.0 to 17.6.0
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/17.5.0...17.6.0)

---
updated-dependencies:
- dependency-name: stylelint
  dependency-version: 17.6.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: stylelint
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-29 22:47:06 +02:00
Freya Gustavsson
46a0f8fc1b
branding: Fix Ubuntu 22.04 logo fetching (#23052)
We previously used `plymouth` package to get the Ubuntu logo, but it
didn't include variants for both light and dark mode which was a bit of
an issue. In Ubuntu 24.04 and higher `base-files` package includes the
normal branding files we need, but we now fail tests as we didn't verify
these files exist on Ubuntu 22.04.

Reverting the change isn't great as we run into the light and dark mode
issues again, but we can conditionally fetch the new logos if they exist
and fallback to `plymouth` for the logo.

Signed-off-by: Freya Gustavsson <freya@venefilyn.se>
2026-03-26 14:32:17 +01:00
Freya Gustavsson
55c69ecfa5
branding: Update Cockpit logo to 2021 variant (#23001)
Recently the Cockpit logo was updated within the website to use a better
font while also moving the Cockpit icon to reduce whitespace issues and
visually center Cockpit's plane within the circle.

This updates the branding section to include the updated logo.

Related-to: https://github.com/cockpit-project/cockpit-project.github.io/pull/472

Signed-off-by: Freya Gustavsson <freya@venefilyn.se>
2026-03-25 11:54:11 +01:00
Jelle van der Waa
d7aa5a3e44 test: exclude packages non-existent on Fedora ELN
Fedora ELN builds Fedora with `%{rhel} == true` so packages which are
not included in RHEL are not available such as udisks2-btrfs and
NetworkManager-team.

https://fmf.readthedocs.io/en/stable/context.html#syntax
2026-03-25 11:53:22 +01:00
Jelle van der Waa
fd35533544 test: exclude btrfs tests on Fedora ELN
Fedora ELN's kernel has no btrfs support nor is udisks2-btrfs available.
2026-03-25 11:53:22 +01:00
GitHub Workflow
ebfa7f09f2 po: Update from Fedora Weblate
Closes #23049
2026-03-25 07:51:17 +01:00
Jelle van der Waa
e204cd130c selinux: allow cockpit-ws to get attributes of pidfs
Addresses the following AVC denial introduced by systemd 260:
avc:  denied  { getattr } for  pid=16530 comm="cockpit-ws" name="/" dev="pidfs" ino=1 scontext=system_u:system_r:cockpit_ws_t:s0 tcontext=system_u:object_r:pidfs_t:s0 tclass=filesystem permissive=0

systemd 260 refactored internal code to use pidfs in most places which
is the likely cause of the new violation.

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2449605
2026-03-23 20:41:30 +01:00
Freya Gustavsson
cfaf4f6c04 branding: Support Ubuntu logo in dark theme
Signed-off-by: Freya Gustavsson <freya@venefilyn.se>
2026-03-23 15:31:06 +01:00
Freya Gustavsson
d2c8be614f branding: Support CentOS logo in dark theme
Signed-off-by: Freya Gustavsson <freya@venefilyn.se>
2026-03-23 15:31:06 +01:00
Freya Gustavsson
e2591ae83b branding: Support RHEL logo in dark theme
Signed-off-by: Freya Gustavsson <freya@venefilyn.se>
2026-03-23 15:31:06 +01:00
Qiaochu Hu
eb139cfcd3
fix: use console.error for error logging in hooks.ts (#23043)
Changed console.log to console.error when logging errors from
cockpit.user() promise rejection. This provides better visibility
of errors in the browser console and follows the convention of
using console.error for error conditions.

Co-authored-by: hobostay <hobostay@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 15:05:53 +01:00
Freya Gustavsson
aacba4292d
packit: Manually download Source0 tar (#23025)
Packit doesn't support downloading all sources and will instead only
download the last Source listed in a specfile. We need to download the
`Source0` manually to get `cockpit.tar.xz` as `Source1` currently points
to `cockpit-node.tar.xz`.

Related-to: https://github.com/cockpit-project/cockpit/issues/22883
Related-to: https://github.com/packit/packit-service/issues/1505
Assisted-by: Claude
Signed-off-by: Freya Gustavsson <freya@venefilyn.se>
Co-authored-by: Maja Massarini <mmassari@redhat.com>
2026-03-23 14:34:29 +01:00
Jelle van der Waa
9532686810 test: drop PowerPC boot partition workaround
The PowerPC boot partition was accidentally created on x86_64 images for
Fedora with the migration to Kiwi. This has long been fixed.
2026-03-23 09:33:10 +02:00
dependabot[bot]
a7008be0cb Bump stylelint from 17.4.0 to 17.5.0 in the stylelint group
Bumps the stylelint group with 1 update: [stylelint](https://github.com/stylelint/stylelint).

Updates `stylelint` from 17.4.0 to 17.5.0
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/17.4.0...17.5.0)

---
updated-dependencies:
- dependency-name: stylelint
  dependency-version: 17.5.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: stylelint
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-22 13:31:55 +01:00
dependabot[bot]
641341c9e8 Bump gettext-parser from 9.0.1 to 9.0.2
Bumps [gettext-parser](https://github.com/smhg/gettext-parser) from 9.0.1 to 9.0.2.
- [Release notes](https://github.com/smhg/gettext-parser/releases)
- [Changelog](https://github.com/smhg/gettext-parser/blob/main/CHANGELOG.md)
- [Commits](https://github.com/smhg/gettext-parser/compare/v9.0.1...v9.0.2)

---
updated-dependencies:
- dependency-name: gettext-parser
  dependency-version: 9.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-22 11:50:35 +01:00
Allison Karlitskaya
6e144bc0be login.js: fix a faulty check on X-Conversation challenges
This code seems to be expecting a header where:
  - the header has 3 parts; and
  - the first part is 'X-Conversation'

but that's not what the check is doing.  It only returns if both checks
fail, which means that the function will continue where:
  - the header has 3 parts; OR
  - the first part is 'X-Conversation'

This means that any three-part header will be accepted (even if it
doesn't start with "X-Conversation") and any header starting with
"X-Conversation" will be accepted, even if it doesn't have three parts.
That last one is a particular problem because the very next thing we do
is try to access the 2nd and 3rd parts, which may not even exist.

This bug goes back at least as far as 74e58fc8c1 ("ws: Support
conversations in authentication") before "X-Conversation" was even the
name of the challenge (it was "X-Login-Reply" at the time).

We can fix it by changing the `&&` here to a `||`: we want to return if
*either* check fails.  Also `!==`, because.
2026-03-20 16:33:43 +01:00
Jelle van der Waa
fd51e22997 pyproject: add minimal ty configuration
ty is a new Python type checker implemented in Rust, its quite a bit
faster then mypy but still experimental.
2026-03-20 16:29:07 +01:00
Jelle van der Waa
69dbb89bf0 common: resolve initialization discards ‘const’ qualifier from pointer target type
In C23 strchr is now implemented different from the POSIX definition and
has two forms:

char       *strchr(char *s, int c);
const char *strchr(const char *s, int c);

Base64 is passed as const, so the return value should also be const.
2026-03-19 14:48:28 +01:00
Freya Gustavsson
159504fca6 style: Update fail.html to PF6
Supports dark style now as taken from our codebase elsewhere. File is
still entirely self-contained and needs no external imports apart from
font.

Changes made:
- Font updated to RH Display Variable Font
- Info icon updated to style in PF6
- Info icon changed to SVG from PNG
- Supports dark theme

Signed-off-by: Freya Gustavsson <freya@venefilyn.se>
2026-03-19 11:15:20 +01:00
Jelle van der Waa
fcfe65722c static: convert the login page to plain CSS
Since 2023 CSS Nesting is baseline supported. [1] Initially it required
one to write `.foo { & .bar { } }` but that restriction has been lifted
for class / id selectors since 2025. To keep maximum compatibility with
older browsers use the & everywhere. Note that for type and pseudo class
selectors an & is always required otherwise it would result into
`.parent-rule *:hover` instead of `.parent-rule:hover`. [2]

The main motivation to move the login page to plain CSS is an idea to
let Anaconda bring their own login.css and not requiring a SASS
compilation step makes that much easier. Secondly for theming it is
easier to reason with a plain CSS file.

[1] https://caniuse.com/css-nesting
[2] https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/Nesting_selector
2026-03-19 10:05:11 +01:00
Jelle van der Waa
2fe4bf75d8 static: login: convert SASS comments to CSS 2026-03-19 10:05:11 +01:00