aboutsummaryrefslogtreecommitdiffstats
path: root/src/routes/blog
diff options
context:
space:
mode:
Diffstat (limited to 'src/routes/blog')
-rw-r--r--src/routes/blog/+page.svelte92
-rw-r--r--src/routes/blog/[id=int]/+page.svelte10
-rw-r--r--src/routes/blog/_posts/+page.server.ts13
-rw-r--r--src/routes/blog/_posts/+page.svelte32
-rw-r--r--src/routes/blog/base-post.svx1
-rw-r--r--src/routes/blog/posts/alpine-ssh-early-initfs.svx113
-rw-r--r--src/routes/blog/posts/test-post.svx3
7 files changed, 222 insertions, 42 deletions
diff --git a/src/routes/blog/+page.svelte b/src/routes/blog/+page.svelte
index 3ce7b0a..fb4592a 100644
--- a/src/routes/blog/+page.svelte
+++ b/src/routes/blog/+page.svelte
@@ -3,6 +3,14 @@
import type { PageProps } from './$types';
let { data }: PageProps = $props();
+ let posts = $derived(
+ Object.entries(data.posts)
+ .filter((v) => v[1].metadata.published === true)
+ .toSorted(
+ ([_, a], [__, b]) =>
+ b.metadata.updated.getTime() - a.metadata.updated.getTime(),
+ ),
+ );
</script>
<svelte:head>
@@ -12,43 +20,55 @@
<div class="flex justify-center">
<div class="max-w-2xl w-full">
<div class="font-genericmono">
- <h1 class="font-space-grotesk text-5xl mt-8 mb-4">
- <span class="text-red-400 select-none">❯&thinsp;</span>ls
- <span class="text-red-400">'</span>blog posts<span class="text-red-400"
- >'</span
- ><span class="text-red-400 select-none">;</span>
- </h1>
- {#each Object.entries(data.posts) as [_filename, post]}
- <div class="flex gap-2">
- <div class="flex flex-col items-end">
- <a
- href={resolve('/blog/[id=int]-[slug]', {
- id: post.metadata.id.toString(),
- slug: post.metadata.slug,
- })}
- class="quicklink">link</a
- >
- <a
- href={resolve('/blog/[id=int]', {
- id: post.metadata.id.toString(),
- })}
- class="quicklink">short</a
- >
- </div>
- <div class="flex flex-col">
- <table>
- <tbody>
- {#each Object.entries( { ...post.metadata, slug: undefined, id: undefined, created: undefined, updated: undefined }, ).filter((v) => v[1] !== undefined) as v}
- <tr>
- <td class="pr-1 align-top">{v[0]}:</td>
- <td class="pl-1 align-top">{JSON.stringify(v[1])}</td>
- </tr>
- {/each}
- </tbody>
- </table>
- </div>
+ {#if posts.length}
+ <h1 class="font-space-grotesk text-5xl mt-8 mb-4">
+ <span class="text-red-400 select-none">❯&thinsp;</span>ls
+ <span class="text-red-400">'</span>blog posts<span
+ class="text-red-400">'</span
+ ><span class="text-red-400 select-none">;</span>
+ </h1>
+ <div class="flex gap-4 flex-col">
+ {#each posts as [_filename, post]}
+ <div class="flex gap-2">
+ <div class="flex flex-col items-end">
+ <a
+ href={resolve('/blog/[id=int]-[slug]', {
+ id: post.metadata.id.toString(),
+ slug: post.metadata.slug,
+ })}
+ class="quicklink">link</a
+ >
+ <a
+ href={resolve('/blog/[id=int]', {
+ id: post.metadata.id.toString(),
+ })}
+ class="quicklink">short</a
+ >
+ </div>
+ <div class="flex flex-col">
+ <table>
+ <tbody>
+ {#each Object.entries( { ...post.metadata, slug: undefined, id: undefined, created: undefined, updated: undefined, published: undefined }, ).filter((v) => v[1] !== undefined) as v}
+ <tr>
+ <td class="pr-1 align-top">{v[0]}:</td>
+ <td class="pl-1 align-top">{JSON.stringify(v[1])}</td>
+ </tr>
+ {/each}
+ </tbody>
+ </table>
+ </div>
+ </div>
+ {/each}
</div>
- {/each}
+ {:else}
+ <h2 class="font-space-grotesk text-5xl mt-8 mb-4">
+ <span class="text-accent-primary select-none">zsh:&ThinSpace;</span>no
+ matches found<span class="text-accent-primary select-none">.</span>
+ </h2>
+ <p class="mt-1.5">
+ Feel free to check back once some posts are published.
+ </p>
+ {/if}
</div>
</div>
</div>
diff --git a/src/routes/blog/[id=int]/+page.svelte b/src/routes/blog/[id=int]/+page.svelte
index 84d33ef..1d8d691 100644
--- a/src/routes/blog/[id=int]/+page.svelte
+++ b/src/routes/blog/[id=int]/+page.svelte
@@ -7,25 +7,25 @@
import { page } from '$app/state';
import { forceTrailingSlash } from '$/lib';
import Post from '$/lib/blog/Post.svelte';
+ import { building } from '$app/environment';
let { data }: PageProps = $props();
- let route = $derived(
+ let route = () =>
forceTrailingSlash(
resolve('/blog/[id=int]-[slug]', {
id: data.post.metadata.id.toString(),
slug: data.post.metadata.slug,
}),
- ),
- );
+ ) + (building ? '' : `${page.url.search}${page.url.hash}`);
onMount(() => {
- tick().then(() => replaceState(route, page.state));
+ tick().then(() => replaceState(route(), page.state));
});
</script>
<svelte:head>
- <link rel="canonical" href={new URL(route, page.url).href} />
+ <link rel="canonical" href={new URL(route(), page.url).href} />
</svelte:head>
<Post post={data.post} filename={data.filename} />
diff --git a/src/routes/blog/_posts/+page.server.ts b/src/routes/blog/_posts/+page.server.ts
new file mode 100644
index 0000000..bc9d5d9
--- /dev/null
+++ b/src/routes/blog/_posts/+page.server.ts
@@ -0,0 +1,13 @@
+import { parsePost, type Post } from '$/lib/blog/Post.svelte'
+
+const posts = import.meta.glob("../posts/*.svx") as Record<string, () => Promise<Post>>
+const returnedData = Promise.all(Object.entries(posts).map(v => v[1]().then(r => [v[0], {
+ ...parsePost(r as Post),
+ default: null,
+}] as const)));
+
+export const load = async () => {
+ return {
+ posts: Object.fromEntries(await returnedData)
+ }
+}
diff --git a/src/routes/blog/_posts/+page.svelte b/src/routes/blog/_posts/+page.svelte
new file mode 100644
index 0000000..2f7ca25
--- /dev/null
+++ b/src/routes/blog/_posts/+page.svelte
@@ -0,0 +1,32 @@
+<script lang="ts">
+ import { resolve } from '$app/paths';
+ import type { PageProps } from '../_/$types';
+ import { browser } from '$app/environment';
+ import { onMount, tick } from 'svelte';
+ import { goto } from '$app/navigation';
+
+ let { data }: PageProps = $props();
+ let posts = $derived(Object.entries(data.posts));
+ onMount(() => {
+ requestAnimationFrame(() => goto(resolve('/blog/')));
+ tick().then(() => goto(resolve('/blog/')));
+ });
+</script>
+
+{#if !browser}
+ {#each posts as a}
+ <!-- svelte-ignore a11y_consider_explicit_label -->
+ <a
+ href={resolve('/blog/[id=int]-[slug]', {
+ id: a[1].metadata.id.toString(),
+ slug: a[1].metadata.slug,
+ })}
+ ></a>
+ <!-- svelte-ignore a11y_consider_explicit_label -->
+ <a
+ href={resolve('/blog/[id=int]', {
+ id: a[1].metadata.id.toString(),
+ })}
+ ></a>
+ {/each}
+{/if}
diff --git a/src/routes/blog/base-post.svx b/src/routes/blog/base-post.svx
index 394eaa2..5a0fa13 100644
--- a/src/routes/blog/base-post.svx
+++ b/src/routes/blog/base-post.svx
@@ -8,6 +8,7 @@ id: -1
# Timestamps are in ISO8601 UTC (`date -u +%Y-%m-%dT%H:%M:%SZ`)
created: "2026-01-14T01:25:14Z"
updated: "2026-01-14T01:25:14Z"
+published: true
---
# Base Post
diff --git a/src/routes/blog/posts/alpine-ssh-early-initfs.svx b/src/routes/blog/posts/alpine-ssh-early-initfs.svx
new file mode 100644
index 0000000..b445127
--- /dev/null
+++ b/src/routes/blog/posts/alpine-ssh-early-initfs.svx
@@ -0,0 +1,113 @@
+---
+title: "Launching SSH during early boot with mkinitfs"
+blurb: "Replacing the early init with our own script to launch SSH, killing it in early userspace, and allowing remote disk decryption in the mean time"
+author: "7222e800"
+slug: "alpine-ssh-early-initfs-disk-decryption"
+id: 1768406136
+
+# Timestamps are in ISO8601 UTC (`date -u +%Y-%m-%dT%H:%M:%SZ`)
+created: "2026-01-14T15:53:57Z"
+updated: "2026-01-14T15:53:57Z"
+published: false
+---
+
+<blockquote class="default-blockquote blockquote-red-400">
+
+ **Warning**<br/>
+ This post talks about operations that may lead the reader's system
+ unbootable, including modifying its initramfs.
+ Do not follow along if the reader is not prepared to fix its own
+ systems from potentially infuriating bugs.
+
+ <p><small class="text-sm opacity-50 hover:opacity-70 transition-opacity">Maybe avoid following along on the friday
+ before the reader's vacation.</small></p>
+
+</blockquote>
+
+For a while, this one's been meaning to setup an early-boot SSH environment for
+Alpine Linux on systems that are using a
+[System Disk](https://wiki.alpinelinux.org/wiki/System_Disk_Mode) installation
+mode.
+
+<!-- TODO: APKOVL boot article -->
+In [Data Disk](https://wiki.alpinelinux.org/wiki/Data_Disk_Mode) mode, it can
+be handled in `boot` or `sysinit`. This can even be nicely netbooted via a
+netbooted apkovl - article on that eventually. (for now, if you're interested
+in that, here's a good starting point:
+[alpine/mkinitfs#cc4954b/initramfs-init.in](https://gitlab.alpinelinux.org/alpine/mkinitfs/-/blob/cc4954bc73cf55833b48624232b9c42ca3abc390/initramfs-init.in#L647))
+
+On System Disk installations, with tooling like [dracut](https://wiki.gentoo.org/wiki/Dracut),
+this would also be trivial. Unfortunately, this one's a masochist and like
+staying close to the intended upstream Alpine installation
+
+> **Note**<br/>
+> Alpine does have
+> [a package](https://pkgs.alpinelinux.org/package/v3.23/community/x86_64/dracut)
+> for dracut, and the reader may want to look into using it instead.
+
+## mkinitfs and it's challenges
+
+Alpine's [mkinitfs](https://gitlab.alpinelinux.org/alpine/mkinitfs/) allows us
+to do things like including files or kernel modules in the image, via their
+[features.d](https://gitlab.alpinelinux.org/alpine/mkinitfs/-/tree/master/features.d).
+
+This is nice and all, but on it's own, we can only really give the kernel a
+module, or a file we manually call by spamming enter through the encryption
+password prompts and running via the 'Emergency Shell'.
+
+
+### approach 1: patching
+
+The easiest solution this one thought of was to just directly modify
+`/usr/share/mkinitfs/initramfs-init` and be happy, then deal with it when
+upstream modifies things.
+
+This is, however, very not "set, make a blog post, and forget". So we skipped
+that idea.
+
+### approach 2: fork the upstream
+
+The second, and nicest to upstream solution it thought of was modify
+[initramfs-init.in](https://gitlab.alpinelinux.org/alpine/mkinitfs/-/blob/cc4954bc73cf55833b48624232b9c42ca3abc390/initramfs-init.in)
+ \- which gets built into `/init` in the initfs.
+
+This would've worked very well, but would require maintaining one's own
+`/init`, for which the distro provides few guarantees that the rest of the
+tooling will forever accomodate an old version forked off.
+
+#### upstreaming
+
+It also thought about upstreaming this, for which this would've been the only
+viable approach. However, with this, comes the challenge of cleaning up the
+sshd during early openrc, cleanly, without any use-case edge-cases.
+
+> **For Alpine Maintainers**<br/>
+> If beings involved in the mkinitfs project want something like this, this
+> one's willing to, with some guidance on avoiding user edge-cases, contribute
+> this.
+
+### approach 3: third approach's the charm
+
+The third approach was wrapping
+[nlplug-findfs](https://gitlab.alpinelinux.org/alpine/mkinitfs/-/blob/cc4954bc73cf55833b48624232b9c42ca3abc390/nlplug-findfs.1.in),
+replacing the system-wide binary, regenerating the initramfs, and then spawning
+SSH from there and directly interacting via libssh.
+
+Whilst this would be sensible in theory, this has a high maintenance burden if
+nlplug-findfs is modified substantially (or, worse, entirely removed). This is
+heavily in no guarantees provided land.
+
+So this one opted against it.
+
+### approach 4: a kernel module
+
+A kernel module could start a userspace process early, which would not involve
+touching any of the existing tooling's code (and just needs one file added).
+
+But also, no.
+
+## starting ssh before `initramfs-init.in`
+
+> "it's like LogoFAIL for your initfs" - somebeing, probably
+
+After roughly a few moments too many than this one'd prefer ot have thought about this, it came to the idea of [TODO: FINISH POST]
diff --git a/src/routes/blog/posts/test-post.svx b/src/routes/blog/posts/test-post.svx
index b12b25a..f828949 100644
--- a/src/routes/blog/posts/test-post.svx
+++ b/src/routes/blog/posts/test-post.svx
@@ -1,5 +1,5 @@
---
-title: "Test Post"
+title: "Test Post: How Testing a Post can Post your Tests"
blurb: "Awawawa Ipsum dolor the neobot is in the washing machine"
author: "7222e800"
slug: "test-post"
@@ -8,6 +8,7 @@ id: -1
# Timestamps are in ISO8601 UTC (`date -u +%Y-%m-%dT%H:%M:%SZ`)
created: "2026-01-14T01:25:14Z"
updated: "2026-01-14T01:25:14Z"
+published: unlisted
---
<script lang="ts">