Skip to content

Feature: permit running anything-sync-daemon as an unprivileged user#85

Open
tomeon wants to merge 124 commits intograysky2:masterfrom
tomeon:unprivileged-operation
Open

Feature: permit running anything-sync-daemon as an unprivileged user#85
tomeon wants to merge 124 commits intograysky2:masterfrom
tomeon:unprivileged-operation

Conversation

@tomeon
Copy link
Copy Markdown

@tomeon tomeon commented Sep 29, 2023

Plus a bunch of other fixes and features. Note that this changeset includes major refactorings; I offer this PR with the expectation that its scope is too large to effectively review and therefore not reasonable to merge. However, I've done my best to test and document the changes, and I think that they are genuinely useful, so if you've got the inclination to review this -- many thanks in advance!

Summary of changes:

  1. Permit running asd as an unprivileged user. This includes installing a systemd user unit, and loading asd.conf from a different location than /etc/asd.conf. I've also added the script asd-mount-helper, based on psd-overlay-helper, to facilitate mounting and unmounting as a non-root user.
  2. Add an anything-sync-daemon Nix package (nix/packages.nix).
  3. Add a NixOS module (nix/nixos-module.nix) for configuring and running system and user instances of asd.service, asd-resync.service, and asd-resync.timer.
  4. Add NixOS-based systems tests (nix/checks.nix) that verify the correct operation of system and user asd services.
  5. Add Nix-based development tooling (nix/devshell.nix), including the shellcheck shell linter and alejandra Nix expression language formatter.
  6. Update the GitHub actions configuration to run the NixOS-based systems tests (and replace the shellcheck workflow, as an equivalent job is included in the Nix checks).
  7. Translate doc/asd.1 to Markdown (in USAGE.md) and generate the manpage from that Markdown. Also expand the documentation to cover environment variables, and add some relevant links.
  8. Factor out sync target iteration (repeated definitions of DIR, BACKUP, TMP, and so on).

I'm still ironing out the GitHub Actions workflow; currently it is quite slow (at least, the NixOS systems tests are). But you can see a recent run here.

Thanks again for your consideration!

along with a `numtide/devshell`-based development shell providing a
command to lint and format shell and Nix code (with, respectively,
shellcheck and alejandra).
@tomeon tomeon force-pushed the unprivileged-operation branch from 96b0a42 to d310643 Compare October 4, 2023 16:30
@manorit2001
Copy link
Copy Markdown
Collaborator

manorit2001 commented Oct 5, 2023

Hi @tomeon, I really like the changes that you have been doing ( just a bird's eye review based on your commits ). Unfortunately , I haven't been able to spend much time to give a detailed review as you already know the changes are humongous and it's not exactly possible to review but I do see that you are active and doing some good improvements based on your commits. I will see if I can review few of the stuff but I can't commit at this stage.

Although, I would like to know a few things. Is there any breaking change in this full PR w.r.t the current asd version and something that you would like to summarise based on that? The debug capability handling along with fixes and added nix os support is always welcomed but the only thing that I am mostly worried about is the compatibility with the current asd version. I see that asd is a very critical piece of software and people have actually suffered data losses in the past due to the refactor and the syncing process, if you know anything that you have done to drastically alter that process ( along with changing any names for the backup folders or anything), I would recommend giving a summary of it and maybe explaining the changes here ( or if possible pointing to those specific commits along with the explanation ) as that'd help us see the scope of the upgradation process from current asd to the new one. Also, I see that most of your testing has been NixOS based, is there anything that you have done for arch or is there some difference in that? I haven't really ventured into NixOS so feel free to impart your knowledge

@tomeon
Copy link
Copy Markdown
Author

tomeon commented Oct 6, 2023

Hello @manorit2001 -- thank you very much for your feedback.

Is there any breaking change in this full PR w.r.t the current asd version and something that you would like to summarise based on that?

If you subscribe to Hyrum's Law, then I'm afraid there are breaking changes in just about every commit 😉 . More seriously: a few of my changes are liable to break some setups, particularly the changes having to do with loading asd.conf and its snapshot. However: setups broken by these changes are probably doing something (a) naughty (like messing with anything-sync-daemon's internal state) or (b) inadvisable (like launching long-running processes). In case (a), users shouldn't do that, and in case (b) there's the workaround/escape hatch of specifying a longer timeout in ASDCONFTIMEOUT.

I see that asd is a very critical piece of software and people have actually suffered data losses in the past due to the refactor and the syncing process, if you know anything that you have done to drastically alter that process ( along with changing any names for the backup folders or anything), I would recommend giving a summary of it and maybe explaining the changes here ( or if possible pointing to those specific commits along with the explanation ) as that'd help us see the scope of the upgradation process from current asd to the new one.

I am working on a CHANGELOG.md that will cover all significant changes, highlighting especially any breaking changes. I have not changed the names of backup folders, and any path-related changes are strictly opt-in, either by (a) running anything-sync-daemon as an unprivileged user (so should not affect existing installations, though I cannot say this for certain) or (b) setting ASDNOV1PATHS=1 or similar, which is not the default.

I see that most of your testing has been NixOS based, is there anything that you have done for arch or is there some difference in that? I haven't really ventured into NixOS so feel free to impart your knowledge

I hadn't done anything for Arch Linux, though, inspired by your mention of it, I've added a Vagrant configuration that spins up an Arch Linux machine and deploys anything-sync-daemon. Found a few bugs in my other changes as a result, so thanks for that 🙂.

Part of what I like about NixOS systems tests is how the testing framework is distributed with nixpkgs, so if you've got the Nix package manager and an internet connection, you're only a few steps from rockin' and rollin' with pkgs.testers.nixosTest. No need to explicitly install additional tooling, or even configure much of anything outside the actual stuff of interest (in this case, settings in the config.services.asd "namespace"), as nixpkgs handles all the QEMU/KVM/networking/etc. stuff out-of-the-box.

However, I am happy to look into rigorous testing on Arch Linux, too. Haven't found any analog of pkgs.testers.nixosTest for Arch, though perhaps Serverspec or InSpec or similar would do the trick. WDYT?

@tomeon tomeon force-pushed the unprivileged-operation branch 2 times, most recently from e61966c to 8d0010d Compare October 8, 2023 22:17
@tomeon
Copy link
Copy Markdown
Author

tomeon commented Oct 9, 2023

I have added the changelog.

@tomeon
Copy link
Copy Markdown
Author

tomeon commented Oct 9, 2023

Also, latest run is passing; see here.

@tomeon tomeon force-pushed the unprivileged-operation branch 2 times, most recently from 15bfa99 to 6bbed5a Compare October 16, 2023 14:31
@tomeon tomeon force-pushed the unprivileged-operation branch from 6bbed5a to b3656bf Compare November 6, 2023 14:26
Copy link
Copy Markdown
Collaborator

@manorit2001 manorit2001 left a comment

Choose a reason for hiding this comment

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

Hey @tomeon, apologies for the delay but you know it's a big PR so had to see what all changes are being done, I still can't cover it thoroughly but trying to gauge the changes being done in this, have some questions as well. Why is shellcheck ci removed btw?

README.md Outdated

Anything-sync-daemon (asd) is a tiny pseudo-daemon designed to manage user
defined dirs in tmpfs and to periodically sync back to the physical disc
(HDD/SSD). This is accomplished via a symlinking step and an innovative use of
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

not symlinking step anymore, I believe it has been changed to bind mounts but a stale documentation, maybe you can update that as well. Can see the arch wiki to be updated as well as your description of Usage.md so maybe fix the stale documents also from there.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Sure; happy to handle these items.

Comment on lines +123 to +128
: A boolean variable controlling whether to use "version 1" paths or not. When
set to a false value, `asd` will use old-style defaults for its daemon file
(`/run/asd`), lock file (`/run/asd-lock`), and configuration file
(`/etc/asd.conf`). **NOTE** that this variable is ignored when `asd` is
running as a non-`root` user. Defaults to disabled (effectively,
`ASDNOV1PATHS=0`).
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What are the paths when this is not enabled? Also, I think renaming this to ASD_BACKWARD_COMPAT would be good ig as it seems like it is something similar to that, this name is a bit confusing for me.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

What are the paths when this is not enabled?

I'll make sure to enumerate these in the documentation. For the systemd asd.service unit, the locations are as follows:

  1. Daemon file, in order of precedence from highest to lowest:
    a. the value of the DAEMON_FILE environment variable, if set and non-empty,
    b. ${ASDRUNDIR}/asd.run, if ASDRUNDIR is set and non-empty,
    c. ${RUNTIME_DIRECTORY%%:*}/asd.run, if RUNTIME_DIRECTORY is set and non-empty (note that RUNTIME_DIRECTORY is a list of colon-separated directories set by systemd on the basis of the RuntimeDirectory directive from the [Service] section of a systemd unit), and, finally,
    d. /run/asd/asd.conf.
  2. Lock file: pretty much the same as the daemon file, with these modifications: the basename is asd.lock, and there is no equivalent DAEMON_FILE-style environment variable that the user can set to an arbitrary path.
  3. Configuration file: /etc/asd/asd.conf.

I think renaming this to ASD_BACKWARD_COMPAT would be good ig as it seems like it is something similar to that, this name is a bit confusing for me.

I think that ASD_BACKWARD_COMPAT is too general; there are any number of ways in which anything-sync-daemon might become backward-incompatible in the future, which implies on or more of the following:

  1. The meaning of ASD_BACKWARD_COMPAT would change over time (the behaviors it controls would differ),
  2. Users would face an all-or-nothing decision: all backward-compatible behaviors, or none, or
  3. We'd have to choose new variable names to control new backward-compatibility-or-not behavior.

I chose ASDNOV1PATHS for the following reasons:

  1. Preexisting ASD* variables all eschew underscores and are all quite terse (though, for what it's worth, in general I like separating semantically-distinct elements with underscores),
  2. The NO bit helps emphasize that this is opt-in behavior and that by default you get the old path scheme, and is less liable to confuse after asd fully deprecates the old path scheme (ASDNOV1PATHS=no will cease to have any effect, whereas ASDNOV1PATHS=yes will, in a sense, remain in effect forever).
  3. The V1 bit scopes the effect to a particular path scheme (that is, the first one), and
  4. The PATHS bit scopes the effect to a particular realm of concern (that is, paths significant to asd).

However, I'd be happy to consider alternatives that satisfy at least some of the desiderata just listed. What do you think about something like ASD_DISABLE_V1_FILE_PATH_SCHEME_COMPAT?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could you clarify why was there a need for this change? Does this help adding support for running asd as an unprivileged user? Basically I want to understand if there was a need or if this a stylistic change only.

' "$0" "${1?}"
}

use_v1_paths() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I am not sure about why we are changing paths btw, what benefits do we get and what paths are we ending up changing?

@manorit2001
Copy link
Copy Markdown
Collaborator

However, I am happy to look into rigorous testing on Arch Linux, too. Haven't found any analog of pkgs.testers.nixosTest for Arch, though perhaps Serverspec or InSpec or similar would do the trick. WDYT?

There is one test that I am particularly worried about first of all with this PR, it is basically the upgrade process, if possible could you check if we use the current asd version, stop asd ( this will happen as the part of upgradation process ) and then update your asd version to the new one with same configs as it was previously, I want to know that nothing breaks as a part of that.

W.r.t inspec or serverspec, I don't have any strong preference as I haven't worked on them, I would recommend you to choose whatever feels scalable to you for the project, would see the changes based on that.

tomeon added 17 commits July 14, 2024 23:29
and expand the `mkFlake` `systems` argument to more supported Linux
architectures.
for managing systemwide and per-user anything-sync-daemon installations.
that exercises various anything-sync-daemon features and behaviors,
including OverlayFS support and crash-recovery backups.
that prints additional context like the source file and current line
number when Bash execution tracing is in effect.
rather than inlining nearly-identical `case` statements for both
and `USE_OVERLAYFS` and `USE_BACKUPS`.
`diag` (simple echo to stderr) and `ediag` (`echo -e` to stderr).  The
intention is to replace uses of `echo` and `echo -e` that write to
stdout.
but instead define the `debug` function so that it is a NOP when `DEBUG`
is disabled.
in preparation for supporting running anything-sync-daemon as a non-root
user.
that is, `set -euo pipefail`.
as we'll be bailing out anyway due to `set -e`.

Quote `help trap`:

    A SIGNAL_SPEC of ERR means to execute ARG each time a command's
    failure would cause the shell to exit when the -e option is enabled.
with the `have_dep` function and its verbose wrapper `have_dep_diag`.

This de-duplicates code in `dep_check`, and also permits code re-use
when checking whether `flock` is available toward the beginning of the
script.

Additionally, clean up the OverlayFS version check in `dep_check` by (a)
using the arithmetic comparison operator `(( ... ))` and (b)
consolidating to a single conditional statement.

Finally, don't bail out at the first failed dependency, but instead
store the non-zero exit status and continue.  This way, the code will
report all missing dependencies in one go.
by (a) handling `FLOCKER` being unset, (b) respecting the choice of Bash
executable by prepending `"$BASH"` to the re-executed command line, (c)
propagating the current shell options by passing `"-$-"`, and (d) using
portable `flock` options (omit `--verbose`, use `-x` rather than `-e`).
and replace it with explicit error messaging mentioning the
configuration file.
via the `source-path=SCRIPTDIR` directive.
using the `:=` "default-assignment" parameter expansion operator.
tomeon added 22 commits July 14, 2024 23:43
to aid in diagnosing issues with asd's mounts
to avoid getting prettified output.
to avoid getting back data for multiple mounts when we just want one.
to better delineate what's being run
to provide additional diagnostics (e.g. exit status) and to avoid
clobbering `xtrace` if it's already enabled.
when caching them for later synchronization, thus better handling funky
filenames.
before shutting off the resync service.
in an attempt to speed up GitHub Actions by running the checks
concurrently.  Involves some not-terribly-attractive monkeypatching,
with attendant stubbing/casting/etc. to satisfy MyPy.
and explain that it should not be used unless `ASDNOV1PATHS` is enabled.
for spawning an Arch Linux machine and provisioning `asd`.
by selecting the first of the colon-separated paths.  This is necessary,
as systemd supports multiple directories specified as
`ConfigurationDirectory=` and `RuntimeDirectory=`.
as asd now uses bind-mounts rather than symlinks for exposing the
tmpfs-es that it manages.
in preparation for creating a Home Manager module that re-uses some code
from the NixOS module.
@tomeon tomeon force-pushed the unprivileged-operation branch from b3656bf to 39e0f19 Compare July 15, 2024 22:51
@tomeon tomeon force-pushed the unprivileged-operation branch from 39e0f19 to f0435de Compare July 21, 2024 02:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants