Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tests: add spread test for passphrase support #14867

Open
wants to merge 8 commits into
base: fde-manager-features
Choose a base branch
from

Conversation

ZeyadYasser
Copy link
Contributor

This PR adds spread tests for passphrase support for hybrid and core24.

Passphrase support has not landed yet, the spread test could be verified against the spike branch if needed.

Hybrid standalone tests:

  • Mimics 25.04 classic model as much as possible.
  • Tests installation with passphrase + first boot.
  • Tests reseals triggered by gadget/kernel refreshes.

Core24 smoke test variant (for Core Desktop):

  • Tests installation with passphrase + first boot.

The added tests are currently disabled to be enabled when the corresponding support lands.
An alternative could be to enable them and have them intentionally fail until support lands.

@github-actions github-actions bot added the Run Nested -auto- Label automatically added in case nested tests need to be executed label Dec 17, 2024
@ZeyadYasser ZeyadYasser added the Run nested The PR also runs tests inluded in nested suite label Dec 17, 2024
@ZeyadYasser
Copy link
Contributor Author

Run nested tests to make sure nothing else broke.

@ZeyadYasser ZeyadYasser reopened this Dec 17, 2024
Copy link

codecov bot commented Dec 17, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 78.19%. Comparing base (25f9119) to head (1d1a2df).

Additional details and impacted files
@@                   Coverage Diff                    @@
##           fde-manager-features   #14867      +/-   ##
========================================================
- Coverage                 78.20%   78.19%   -0.01%     
========================================================
  Files                      1171     1171              
  Lines                    155885   155847      -38     
========================================================
- Hits                     121903   121869      -34     
- Misses                    26450    26453       +3     
+ Partials                   7532     7525       -7     
Flag Coverage Δ
unittests 78.19% <ø> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@ZeyadYasser ZeyadYasser added Needs Samuele review Needs a review from Samuele before it can land FDE Manager Pull requests that target FDE manager branch Skip spread Indicate that spread job should not run and removed Run Nested -auto- Label automatically added in case nested tests need to be executed Skip spread Indicate that spread job should not run labels Dec 17, 2024
# Open port 7777 on the host so that failures in the nested VM (e.g. to
# create users) can be debugged interactively via
# "telnet localhost 7777". Also keeps the logs
#
# XXX: should serial just be logged to stdout so that we just need
# to "journalctl -u $NESTED_VM" to see what is going on ?
if "$QEMU" -version | grep '2\.5'; then
if [ -z "$EXPECT_PASSPHRASE" ]; then
echo "internal error: NESTED_EXPECT_PASSPHRASE is set and qemu doesn't support chardev over socket"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you remember which systems this old version appears on?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tests/lib/nested.sh Show resolved Hide resolved
tests/nested/manual/passphrase-support-on-hybrid/task.yaml Outdated Show resolved Hide resolved
tests/nested/manual/passphrase-support-on-hybrid/task.yaml Outdated Show resolved Hide resolved
tests/nested/manual/passphrase-support-on-hybrid/task.yaml Outdated Show resolved Hide resolved
tests/nested/manual/passphrase-support-on-hybrid/task.yaml Outdated Show resolved Hide resolved
tests/nested/manual/passphrase-support-on-hybrid/task.yaml Outdated Show resolved Hide resolved
tests/nested/manual/passphrase-support-on-hybrid/task.yaml Outdated Show resolved Hide resolved
@github-actions github-actions bot added the Run Nested -auto- Label automatically added in case nested tests need to be executed label Dec 20, 2024
@ZeyadYasser ZeyadYasser requested a review from bboozzoo December 20, 2024 13:30
Comment on lines 102 to 103
local expect_passphrase=${3:-}
local log_file=${4:-}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$3 and $4 should be defined if we expect $5 to be defined also.

Copy link
Contributor Author

@ZeyadYasser ZeyadYasser Jan 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But they are optional, similar to --wait and --attempts, no? I might be confused.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aah I missed this is snapd-testing-tools, so the changes to this file should go to this repo https://github.com/snapcore/snapd-testing-tools and once they land we sync them

Copy link
Contributor Author

@ZeyadYasser ZeyadYasser Feb 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created a PR canonical/snapd-testing-tools#56, but now that I think about it since this is a one off, then maybe I should be entering the passphrase in the test script itself, not as a part of remote.wait-for, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UPDATE: I changed the test to do the waiting for the passphrase prompt inline, and reverted the changes to remote.wait-for.

echo "remote.wait-for --expect-passphrase without passing an existing --log-file"
return 1
fi
while [ "$attempts" -ge 0 ]; do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for loop maybe?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The attempt was to be consistent with the loop below, I will update both to be a for loop.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, it seems that all remote.wait-for helpers use while, maybe this can be refactored in a followup PR so the script is consistent.

# Wait for passphrase prompt from serial log file.
if MATCH "Please enter the passphrase" < ${log_file}; then
# Enter passphrase to continue boot.
echo "$expect_passphrase" | netcat -N localhost 7777
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we use bash, maybe we can use /dev/tcp/localhost/7777 instead of relying on an external tool that has lots of forks and different command lines.

Or even better, switch that to a unix socket.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd check how far back support for tcp sockets in bash goes, so that we're not surprised by some old version

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was not able to get it working with tcp sockets, even locally. I couldn't get qemu to understand that connection is closed and interpret a \n or \r to enter the passphrase.

Comment on lines 145 to 159
muinstaller_args="-label $label -device $install_disk -rootfs-creator /snap/muinstaller/current/bin/mk-classic-rootfs.sh"
if [ -n "$passphrase" ]; then
muinstaller_args="$muinstaller_args --passphrase $passphrase"
fi
if [ -n "$extra_muinstaller_args" ]; then
muinstaller_args="$muinstaller_args $extra_muinstaller_args"
fi
remote.exec "sudo muinstaller $muinstaller_args"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we could get rid of this big string pass as parameter to remote.exec and use lists instead.

@@ -19,6 +19,8 @@ run_muinstaller() {
local kernel_assertion="${6}"
local label="${7}"
local disk="${8}"
local passphrase="${9}"
local extra_muinstaller_args="${10}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we just shift then take the whole "$@"?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually there's something fishy about existing code, store_dir is optional? fortunately there do not seem to be any calls to run_muinstalled that omit store_dir in arguments

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bboozzoo good point about store_dir, I was concerned at first, but turns out that passing args as ${arg} passes them even if they are empty, so order is preserved.

echo "This test needs test keys to be trusted"
exit
fi
apt install dosfstools kpartx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment about what uses those.

Because specially I am not fan of kpartx, and I would like to know if we can just remove it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you move dosfstools to the prepare section of tests/nested/manual in spread.yaml? FWIW, those should already be present anyway, so I'm not sure why we need to install them explicitly, perhaps it works without the package too?

As for kpartx it's likely some legacy thing that's incorrectly perpetuated, the prepare sections of tests/nested in spread.yaml list it, but AFAIK we do not need it, neither does ubuntu-image, so if possible we could use it as an opportunity to remove it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kpartx is used inside tests/lib/tools/setup_nested_hybrid_system.sh, also fatlabel which is provided by the dosfstools package is also used inside tests/lib/tools/setup_nested_hybrid_system.sh.

I will try to move them up into prepare of tests/nested/manual

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

turns out kpartx is already installed in nested prepare for all variants

remote.exec "sudo apt install -y update-notifier-common"
# Initial reseal count.
remote.exec sudo cat /var/lib/snapd/device/fde/boot-chains > boot-chains-before.json
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we will need to remove this file at some point. I would prefer if we stop adding tests that rely on it.

This file is mostly used to cache and avoid recomputing input for the pcr profiles. But since we have a FDE state now, we will be able to looking into ditching it. So please, do not use that.

You could query the state and look if the pcr profile changed maybe instead.

Comment on lines 120 to 125
# Check that on an already provisioned system the API will give a
# sensible reason why the system cannot be installed without further
# action.
remote.exec "sudo snap debug api /v2/systems/classic" > system
gojq '.result."storage-encryption".support' < system | MATCH "unavailable"
gojq '.result."storage-encryption"."unavailable-reason"' < system | MATCH "not encrypting device storage as checking TPM gave: the TPM is in DA lockout mode"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit confusing. I am not sure why we test this here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied that check from muinstaller-real. you are right, it is not relevant here.

Comment on lines 144 to 148
# Check that a reboot notification was setup.
remote.exec test -f /run/reboot-required
remote.exec cat /run/reboot-required.pkgs | MATCH "snap:${snap_name}"
# Check that no reboot has been scheduled, then force a reboot
remote.exec not test -f /run/systemd/shutdown/scheduled
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is not this going to change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I fully understand

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I think this could be removed

printf "Test installing snap from file %s\n" "$snap_filename"
remote.push "$snap_filename"
# install will exit when waiting for the reboot
remote.exec sudo snap install --dangerous "$snap_filename" | MATCH "Task set to wait until a system restart allows to continue"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does not this one depend on reboot_action?

-rootfs-creator /snap/muinstaller/current/bin/mk-classic-rootfs.sh"
muinstaller_args="-label $label -device $install_disk -rootfs-creator /snap/muinstaller/current/bin/mk-classic-rootfs.sh"
if [ -n "$passphrase" ]; then
muinstaller_args="$muinstaller_args --passphrase $passphrase"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
muinstaller_args="$muinstaller_args --passphrase $passphrase"
muinstaller_args="$muinstaller_args --passphrase "$passphrase""

just out of curiosity, I'd check whether a passphrase containing a space character is correctly handled.

@@ -19,6 +19,8 @@ run_muinstaller() {
local kernel_assertion="${6}"
local label="${7}"
local disk="${8}"
local passphrase="${9}"
local extra_muinstaller_args="${10}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually there's something fishy about existing code, store_dir is optional? fortunately there do not seem to be any calls to run_muinstalled that omit store_dir in arguments

echo "This test needs test keys to be trusted"
exit
fi
apt install dosfstools kpartx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you move dosfstools to the prepare section of tests/nested/manual in spread.yaml? FWIW, those should already be present anyway, so I'm not sure why we need to install them explicitly, perhaps it works without the package too?

As for kpartx it's likely some legacy thing that's incorrectly perpetuated, the prepare sections of tests/nested in spread.yaml list it, but AFAIK we do not need it, neither does ubuntu-image, so if possible we could use it as an opportunity to remove it.

@ZeyadYasser ZeyadYasser force-pushed the add-passphrase-support-spread-test branch from 71c83de to afce113 Compare January 13, 2025 14:05
@ZeyadYasser ZeyadYasser force-pushed the add-passphrase-support-spread-test branch from 6d526ac to c26ec1b Compare January 14, 2025 12:48
@ZeyadYasser ZeyadYasser force-pushed the add-passphrase-support-spread-test branch from c08093a to 6a9cd05 Compare January 28, 2025 08:32
@ZeyadYasser ZeyadYasser added this to the 2.68 milestone Jan 28, 2025
@pedronis pedronis force-pushed the fde-manager-features branch from 7005c64 to 25f9119 Compare January 29, 2025 10:49
This spread test is disabled currently since the corrosponding
passphrase support didn't land yet.

Signed-off-by: Zeyad Gouda <[email protected]>
@ZeyadYasser ZeyadYasser force-pushed the add-passphrase-support-spread-test branch from 6a9cd05 to 1d1a2df Compare January 29, 2025 11:32
@ZeyadYasser
Copy link
Contributor Author

Rebased on top of latest fde branch

Copy link

github-actions bot commented Jan 29, 2025

Tue Feb 4 19:02:03 UTC 2025
The following results are from: https://github.com/canonical/snapd/actions/runs/13139362266

Failures:

Preparing:

  • google-nested:ubuntu-20.04-64:tests/nested/core/
  • google-nested:ubuntu-20.04-64:tests/nested/manual/remodel-offline:local_and_installed_snaps
  • google-nested:ubuntu-20.04-64:tests/nested/manual/remodel-offline:local_assertions
  • google-nested:ubuntu-20.04-64:tests/nested/manual/core20-grade-signed-above-testkeys-boot:secured
  • google-nested:ubuntu-20.04-64:tests/nested/manual/uc-update-assets-secure-add-sbat:both
  • google-nested:ubuntu-20.04-64:tests/nested/manual/core20-remodel
  • google-nested:ubuntu-20.04-64:tests/nested/manual/recovery-system:tested
  • google-nested:ubuntu-20.04-64:tests/nested/manual/remodel-uc20-to-uc22:encrypted
  • google-nested:ubuntu-20.04-64:tests/nested/manual/core20-save:encrypted
  • google-nested:ubuntu-22.04-64:tests/nested/core/core22-basic:tokens
  • google-nested:ubuntu-22.04-64:tests/nested/core/core20-kernel-failover:nolink
  • google-nested:ubuntu-22.04-64:tests/nested/manual/recovery-system-reboot:factory_reset
  • google-nested:ubuntu-22.04-64:tests/nested/manual/core20-cloud-init-maas-signed-seed-data:gadgetsaysmaas
  • google-nested:ubuntu-22.04-64:tests/nested/manual/recovery-system-reboot:recover
  • google-nested:ubuntu-24.04-64:tests/nested/core/interfaces-custom-devices
  • google-nested:ubuntu-24.04-64:tests/nested/manual/hybrid-remodel
  • google-nested:ubuntu-24.04-64:tests/nested/manual/uc20-fde-hooks:tokens
  • google-nested:ubuntu-24.04-64:tests/nested/manual/recovery-system-reboot:recover
  • google-nested:ubuntu-24.04-64:tests/nested/manual/recovery-system-reboot:factory_reset

Executing:

  • google-distro-1:debian-11-64:tests/unit/go:gcc
  • google-nested:ubuntu-20.04-64:tests/nested/manual/remodel-offline:local_snaps
  • google-nested:ubuntu-20.04-64:tests/nested/manual/remodel-offline:installed_snaps
  • google-nested:ubuntu-22.04-64:tests/nested/manual/core20-set-efi-boot-vars:UBUNTUDIR
  • google-nested:ubuntu-22.04-64:tests/nested/manual/split-refresh
  • google-nested:ubuntu-24.04-64:tests/nested/core/core22-basic:tokens
  • google-nested:ubuntu-24.04-64:tests/nested/core/core20-fault-inject-on-refresh:kernel_reboot_auto_connect
  • google-nested:ubuntu-24.04-64:tests/nested/manual/muinstaller-real:encrypted
  • google-nested:ubuntu-24.04-64:tests/nested/manual/muinstaller-real:partial
  • google-nested:ubuntu-24.04-64:tests/nested/manual/remodel-min-size
  • google-nested:ubuntu-24.04-64:tests/nested/manual/muinstaller-real:seeded
  • google-nested:ubuntu-24.04-64:tests/nested/manual/muinstaller-real:plain
  • google-nested:ubuntu-24.04-64:tests/nested/manual/muinstaller-core:plain
  • google-core:ubuntu-core-18-64:tests/core/kernel-base-gadget-pair-single-reboot:gadget_base
  • google-core:ubuntu-core-20-64:tests/core/services

Restoring:

  • google-nested:ubuntu-22.04-64:tests/nested/manual/core20-cloud-init-maas-signed-seed-data:gadgetsaysmaas
  • google-nested:ubuntu-22.04-64:tests/nested/manual/
  • google-nested:ubuntu-22.04-64
  • google-nested:ubuntu-22.04-64:tests/nested/manual/recovery-system-reboot:recover
  • google-nested:ubuntu-22.04-64:tests/nested/manual/
  • google-nested:ubuntu-22.04-64
  • google-nested:ubuntu-24.04-64:tests/nested/manual/recovery-system-reboot:factory_reset
  • google-nested:ubuntu-24.04-64:tests/nested/manual/
  • google-nested:ubuntu-24.04-64
  • google-core:ubuntu-core-18-64:tests/core/kernel-base-gadget-pair-single-reboot:gadget_base
  • google-core:ubuntu-core-18-64:tests/core/
  • google-core:ubuntu-core-18-64

@pedronis
Copy link
Collaborator

Replacing myself here with Alfonso that should know about the muinstaller etc

@pedronis pedronis removed their request for review January 31, 2025 09:21
Comment on lines 102 to 103
local expect_passphrase=${3:-}
local log_file=${4:-}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
local expect_passphrase=${3:-}
local log_file=${4:-}
local expect_passphrase=${3}
local log_file=${4}

(and the same for the 2 preceding lines)

I think I'd drop the undefined expansion and simply let it fail to catch the bugs in how this function is called. We're expecting all positional arguments being passed to this function anyway

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reverted the changes to remote.wait-for in favor of doing the waiting for the passphrase prompt inline in the test script directly. No need to change testing tools for a one off case like passphrases.

# Wait for passphrase prompt from serial log file.
if MATCH "Please enter the passphrase" < ${log_file}; then
# Enter passphrase to continue boot.
echo "$expect_passphrase" | netcat -N localhost 7777
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd check how far back support for tcp sockets in bash goes, so that we're not surprised by some old version

@ZeyadYasser ZeyadYasser force-pushed the add-passphrase-support-spread-test branch from 1d19d37 to 685389a Compare February 4, 2025 15:49
@ZeyadYasser ZeyadYasser requested a review from bboozzoo February 4, 2025 15:57
Copy link
Member

@alfonsosanchezbeato alfonsosanchezbeato left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, some small comments. I am not sure if we should merge this until the feature branch is merged though.

"architecture": "amd64",
"timestamp": "2024-04-09T22:00:00+00:00",
"grade": "dangerous",
"base": "core22",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably want core24 here. Or is it maybe necessary because the kernel in classic-24.10/edge uses core24 incorrectly?

@@ -1204,13 +1204,20 @@ nested_start_core_vm_unit() {
PARAM_RTC="${NESTED_PARAM_RTC:-}"
PARAM_EXTRA="${NESTED_PARAM_EXTRA:-}"

local EXPECT_PASSPHRASE
EXPECT_PASSPHRASE=${NESTED_EXPECT_PASSPHRASE:-}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that the practice is insted to have a statement like : "${NESTED_EXPECT_PASSPHRASE:=}" at the bgining of nested.sh

Comment on lines +171 to +173
muinstaller_args+=("-label $label")
muinstaller_args+=("-device $install_disk")
muinstaller_args+=("-rootfs-creator /home/user1/mk-classic-rootfs-wrapper.sh")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't each argument be separate? Like args+=("-label" "$label"), etc. I think that in the end is not relevant as remote.exec somewhat is possibly splitting arguments, but still.

@@ -196,7 +204,11 @@ EOF
fi

# Start installed image
tests.nested create-vm core --keep-firmware-state
if [ -n "$passphrase" ]; then
tests.nested create-vm core --keep-firmware-state --expect-passphrase "$passphrase"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: maybe better just --passphrase? expect-passphrase sounds a bit like a boolean.

@@ -338,7 +360,7 @@ main() {

run_muinstaller "${model_assertion}" "${store_dir}" "${gadget_snap}" \
"${gadget_assertion}" "${kernel_snap}" "${kernel_assertion}" "${label}" \
"${disk}" "${kern_mods_comp}"
"${disk}" "${kern_mods_comp}" "${passphrase}" "${extra_muinstaller_args[@]}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way it is initialized, you get only one argument here, ${extra_muinstaller_args[0]}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
FDE Manager Pull requests that target FDE manager branch Needs Samuele review Needs a review from Samuele before it can land Run Nested -auto- Label automatically added in case nested tests need to be executed Run nested The PR also runs tests inluded in nested suite
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants