Friday, November 25, 2022

The Devil is in the Details

We had an initial vision for canceling a contract: choose the contract, input an effective date, and click Cancel.

Then users wanted to get a preview of the cancellation, with all fully-calculated refund values.  We had the preview write everything to the database, and if the user confirmed it, we would mark the cancellation as “complete.”  A user could also “revoke” cancellation, which would delete the pending cancellation.

Soon, we had a system to recover abandoned cancellations by reminding users they had one pending, and auto-revoke it after a deadline.

Then it became clear that there could be race conditions.  What if the cancellation is processed between receiving the notification and following the link enclosed?  What if someone else was running the cancellation on the same contract simultaneously, and ended up with the same results?  We needed to show the new status.

What if someone made a mistake with the inputs?  We needed an “Edit” button that would go back, as well.  If there’s an Edit button, and someone comes in from the main menu, should we reload the inputs, or skip the input screen entirely?

It wasn’t long before Accounting wanted a “reinstate” button.  Suddenly, the “final” state was no longer final.  In the mean time, we had integrated automatic data pushes to the actual accounting software, which meant a huge mess if they wanted to reinstate one that was on the official record as canceled.

If there’s a moral to this, it’s that any software pipeline should be fully reversible, even into the parts where “we sent money out, and we have to ask for it back as a consequence.”

Monday, October 17, 2022

systemd User Service Sandboxing

systemd-analyze security --user SERVICE is handy, but inaccurate.  The analysis (on the version bundled with Ubuntu 22.04 “Jammy”) has a few items that are marked as not applicable to user services, but also recommends setting a few items that apparently cannot be set in a user service. Attempting to do so will fail to start the service, with a log that the capabilities could not be set (regardless of the specific option causing the error.)

This unfortunately restricts the following: CapabilityBoundingSet, PrivateDevices, ProtectClock, ProtectKernelLogs, and ProtectKernelModules.

Using ProtectHostname with RestrictNamespaces=true logs a warning every time the service starts up, because the UTS namespace can’t be configured. It’s only a warning, which I think means that ProtectHostname is redundant in this situation, so I took it out of the service.  It’s more important to have clean logs than a good systemd-analyze security score.

The list of capabilities I was able to set were: KeyringMode=private, LockPersonality=true, MemoryDenyWriteExecute=true, NoNewPrivileges=true, PrivateMounts=true, PrivateTmp=true, ProcSubset=pid, ProtectControlGroups=true, ProtectHome=read-only, ProtectKernelTunables=true, ProtectSystem=strict, RestrictNamespaces=true, RestrictRealtime=true, RestrictSUIDSGID=true, SystemCallArchitectures=native, SystemCallFilter=@system-service, UMask=077, and:

RestrictAddressFamilies=
RestrictAddressFamilies=AF_INET
RestrictAddressFamilies=AF_INET6

Note that this is tailored to the service I was configuring, an HTTP proxy written in Go.  For instance, I wanted to run the binary and load its configuration file from ~/.local, which prevented me from using a stronger setting for ProtectHome.  Likewise, I can’t really turn off networking, because it’s a network program.

Friday, October 14, 2022

An Incomplete API: PSR-7 and PSR-18

Consider some code that is using http-factory-discovery to avoid depending directly on specific PSR-7 and PSR-18 implementations. However, the concrete classes may default to an infinite request timeout, in an environment where external forces (AWS ALB) will time out in 60 seconds. Therefore, in order to return a nicer error message, or get a chance to retry, one wishes to set a timeout like 25 seconds on the request.  Can it be done?

Not really!

A PSR-18 HTTP client has an interface consisting of a single defined method: sendRequest(RequestInterface $request): ResponseInterface.  There is no concept of options here.  The only hope would be to carry them as attributes on the request.

Unfortunately, there are no standard request attributes for HTTP options like this.  PSR-7 defines the attribute mechanism, but is silent about its usage. On the “real world usage” side, Guzzle 7 does not define any way to carry HTTP client options on the Request.

This makes the APIs easier to implement, but leaves a gap in them.  The only way out is to use a specific, concrete implementation.  And then what is the point of the discovery library?  If the application must contain its own code to work with underlying libraries, then all discovery does is add the possibility of returning an unrecognized type.  At that point, the app can only choose between running with degraded features, and crashing entirely.

Wednesday, October 12, 2022

Pop!_OS ‘Unboxing’ Experience

Editor’s Note: This article does not appear to have been published when written, about two weeks into using and customizing Pop!_OS.  This entry contains the original draft, followed by the two-month update.

Initial Thoughts

It took me a while to get settled into Pop!_OS on the new work laptop.  Of course, after leaving a fairly vanilla Ubuntu 10.04 LTS “Lucid Lynx” for Windows in 2012, and using Mac OS X (Mountain Lion through Catalina) at work over roughly the same time period, there was bound to be an adjustment period.  I will focus on bits of the user experience that really stand out as being subpar here; no “oh no, the shortcut is different.”

(For a snapshot of the times: Ubuntu 10.04 would have been using Gnome 2.30, Firefox 3.6, Python 2.6, and Linux 2.6.32.  KDE 4.4 was available, marking Canonical’s first LTS with a KDE 4 version.  It was the first to abandon brown-and-orange as the color theme.  Judging by reviews, the Zune Marketplace still existed at that time, too.)

Perhaps the first thing I noticed was the lack of a maximize button on the windows.  This seemed particularly weird, because the functionality was still present with a double-click in the title bar, or Super+M.  It would be a few days before I would accidentally scroll the settings pane and reveal toggles for both Minimize and Maximize buttons.  The settings window and the hidden scrollbar had conspired to look exactly like a non-scrollable window.

Another peculiarity is the lack of some settings within Settings: both the “Extensions” and “Startup Applications” are completely separate.  Extensions have their own settings pages within that app, except that COSMIC components may not have settings, or may have a settings page with a message that they can be configured from the Desktop section in the Settings app.

Bear in mind that I mostly haven’t used Gnome in a decade, particularly because Gnome 3 upended everything.  (I would later learn that some of this was aping the Mac instead of aping Windows; hurrah for open source “innovation.”) Thus, I’m not entirely sure of what the boundary between Gnome and Pop!_OS’ customizations are, but the end result is rather confusing.  Is this layout logical to someone, or am I looking at a manifestation of Conway’s Law?

Two Month Update

I think it’s Conway’s Law.  It’s rather under-documented which component provides which features, but through experimentally turning Pop Shell off and on, I have learned that it is responsible for:

  1. The good/nice launcher on Super+/
  2. The “focus the window in a direction” shortcuts, Super+(Arrow key)
  3. The window-tiling menu/feature, shown in the system menu area

Getting information on Pop!_OS has been a bit of a problem.  Because it partially customizes Gnome, information on the internet for Gnome may not apply.  Because it is semi-modular, if any of the Pop-specific components are turned off, then information about Pop may also not apply.  Although, that is kind of my fault for not leaving everything on.

However, there’s also a curious benefit to having multiple systems in use: if one breaks, the other may still work.  At some point, launching Flatpaks (which I have put in the system repository) via the Dock started freezing the UI for a bit, not even responding to mouse-move. On the other hand, launching them through Pop Shell’s Super+/ launcher causes no trouble whatsoever.

Having lived at many places on the “up-to-date” vs “actually works” spectrum, and being old and grumpy, my own preference is for something more-working than Pop!_OS, even if it’s less up-to-date.  It might be a while before I go to the effort, though, partly because this is my first EFI/secure boot system, and I don’t want to break it.  Work depends on this hardware.

Sunday, October 9, 2022

Void Linux first impressions

Note: Void Linux may have updated Firefox since this post was originally drafted on 2022-09-25.  The point remains that it was terribly outdated when observed.

I tried Void Linux… twice.  The first time, in VirtualBox, I got DenverCoder’d: the guest additions package was missing, and none of the incantations would bring it out of hiding.  I even copied and pasted the package name to ensure no typos were made.

The next attempt, I put it in virt-manager.  After installing, there was an surprisingly large system update required, which only brought Firefox forward to 91.10.0 ESR.  Today, the entire 91.x branch is no longer being updated (as Firefox 105 and 102.3 ESR have been released), and even “.10” is three releases behind.

This does not bode well for the security of the piece of software that will face the most hostile code.

Beyond that, the keyboard layout was an extreme usability problem.  I haven’t typed on Qwerty as a primary layout in 20 years, and it turns out that I’m losing the ability to switch my brain back to Qwerty at all.  Despite choosing the Dvorak variant in the installer (and the live environment via setxkbmap), the installed system needed some particularly arcane config editing to get Dvorak fully in place.  X11 runs without an Xorg.conf, so one is expected to create /etc/X11/xorg.conf.d and drop a fragment in there, instead, which must be written from scratch.  There were no on-disk examples found.

I will note that I could have set XFCE itself to use Dvorak instead of the system settings, but that would not have altered the login screen.

Despite the XFCE+musl installer being over 800 MB, it did not install an email client.  In fact, it seems like there are only settings, Firefox, and a terminal.  Maybe the installer has great potential for size reduction.

I still don’t know what the point of XBPS is.  It doesn’t seem to be particularly interesting from a user perspective.  The options remind me of pacman but that’s about it.

In any case, like Puppy, I’ve reached the point where I don’t know what to do with the installation next, because I didn’t have plans for it from the start. I just wanted to get a feeling for it.  I know they wrote their own package manager (which looks suspiciously similar to pacman at the UI level), but I don’t really know why. Nothing jumps out as being particularly better/different about it.

Thursday, September 22, 2022

Puppy Linux First Impressions

I’ve used a lot of mainstream systems.  For the past 10 years, my primary desktops have been Mac (work) and Windows (home); before then, I spent over a decade moving through Red Hat 7, FreeBSD 4, Gentoo, Kubuntu 7.04, and regular Ubuntu through 10.04.  I spent memorable chunks of time using fwvm2, WindowMaker, Gnome 1, and KDE 3.  After an experiment with Amazon Linux 1, work standardized on Ubuntu for servers, starting with 14.04.

I say all this to say, I had some warning that Puppy Linux™ was different; there was something about filesystem “layers” and, in theory, being able to build your own like a mixtape. Well, it delivered on being different.

Because first, I had to set up my network.  I found out that a decent chunk of the help is actually online, so I was greeted with Pale Moon telling me “server not found” a few times.  I had the driver files available, but I didn’t have the devx or kernel-sources SFS layers.  I managed to find them on SourceForge, and once the driver installed (quite seamlessly, no-dkms mode), I finally got a network configured with the most-advanced wizard.  It seems that is the only place to be offered to allow WPA2 to be used with the device, since it (or its driver?) isn’t allow-listed already.

I updated Pale Moon, and then, since I was online, why not visit tumblr?  The dash rendered fine, albeit chewing on 100% of a CPU core, but then asking to make a new post crashes (white screen) once the editor loads.  I did not get to announce to the world that I was using Puppy, from Puppy.

(Because my toolchain for Decoded Node posts is on Windows, I am not making this post from Puppy, either.)

The next thing I need to do is figure out what I want to do with this thing. I don’t really have a goal for it yet.

Tuesday, August 30, 2022

Downgrading macOS Catalina to High Sierra

According to Apple Support, my old iMac can be used in Target Display Mode if it’s running High Sierra or earlier. However, I had upgraded it to Catalina.  Getting it back down to High Sierra proved to be quite the challenge.

Part 1: Easy-to-find stuff, cataloged for posterity

I was able to find the installers via Internet search, but after downloading it to the iMac, it wouldn’t run. It claimed that Catalina was too old, which seems like a bad error message for a two-sided version check (Catalina is actually too new, but they didn’t expect they would need to say that.)

However, once again, the Internet came to the rescue: I could use the command- line script bundled with the installer to write it to a USB stick.  It seems that Apple has this answer as well; in my case, it was this:

sudo "/Applications/Install macOS High Sierra.app/Contents/Resources/createinstallmedia" --volume /Volumes/BIT_BUCKET

(Any new-lines in the above command should be entered as spaces at the Terminal prompt.)

The command took about five minutes, but during one dead-end, I found it takes 30 minutes to copy to a USB 2.0 stick.

Part 2: The other roadblocks

The High Sierra installer acted like it couldn’t handle the Catalina disks, and did not quite know how to error out properly.  The installer would ask for the password twice, then… would not unlock the disk.  Clicking “Unlock…” to attempt to proceed would then do nothing.  Trying to mount the volumes first, using Disk Utility, didn’t improve the situation.

I tried to erase the volumes using the installer’s Disk Utility, but it hung on “deleting volume.”  Going to choose a startup disk when the volume was hypothetically deleted didn’t show it, but rebooting would prove that the volume was there.  Incidentally, quitting the startup disk selection would remove the menu bar and leave a featureless gray screen.  Oops.

I ran First Aid, turned off FileVault, and even reinstalled Catalina along the way, but none of that seemed to do anything.

What ended up working was to boot into Catalina’s recovery environment, select “show all devices” in its Disk Utility, then erase the entire APFS container and replace it with a “macOS Extended (Journaled)” disk.  After that point, booting the iMac would bring it into a new menu that looked like “choose startup disk” with no disks.

I had to unplug and re-plug the USB stick for it to show up, and then I could boot from it and install High Sierra in the usual manner.  Success!

Part 3: The cable failure

(Section added 2022-09-03.)

I missed the information that Target Display Mode specifically requires a Thunderbolt 2 cable. The Thunderbolt 3 to mini DisplayPort cable I actually bought fits physically, but does not function.

Moreover, the standard was completely revamped for version 3, so it requires an active adapter for Thunderbolt 2, and a specific Thunderbolt 2 cable. Between them, the current price is about $140, while a new monitor can be had for $200.

I have decided to declare the experiment a failure, and abandon the effort to have an external display for the laptop.

The future may eventually hold a 5K display, shared between the work laptop and my personal desktop, once that requires an upgrade.  My current CPU (the third PCIe GPU died years ago, so I quit putting them in) is rated for 2K output over a port that the motherboard doesn't have, or 1920x1200 otherwise.

Bonus chatter

My USB stick was named BIT_BUCKET because, once in a while, the stick would occasionally forget it had data, or even a filesystem.  But, it managed to survive long enough to get the macOS installer running.