Fossil SCM

Added §5.6 to the containers doc, "Email Alerts," explaining how to get email alerts out by use of the included tools/email-sender.tcl script and the "write mail to DB" feature since the default option (sendmail -ti) won't work by default and it wouldn't be appropriate to make it work besides. This then obviated the earlier half-baked advice on injecting a Tcl environment into the container; the essential point is adequately made by the Python example, so there is no point trying to rescue this plan.

wyoung 2023-09-18 22:10 trunk
Commit 616a37f4f71e7b3acf0a68669ec830b5c946bcf0a912a346b81007bde00e5cd8
1 file changed +81 -45
+81 -45
--- www/containers.md
+++ www/containers.md
@@ -440,54 +440,18 @@
440440
Rebuild and redeploy to give your Fossil container a [BusyBox]-based
441441
shell environment that you can get into via:
442442
443443
$ docker exec -it -u fossil $(make container-version) sh
444444
445
-(That command assumes you built it via “`make container`” and are
446
-therefore using its versioning scheme.)
447
-
448
-Another case where you might need to replace this bare-bones “`run`”
449
-layer with something more functional is that you’re setting up [email
450
-alerts](./alerts.md) and need some way to integrate with the host’s
451
-[MTA]. There are a number of alternatives in that linked document, so
452
-for the sake of discussion, we’ll say you’ve chosen [Method
453
-2](./alerts.md#db), which requires a Tcl interpreter and its SQLite
454
-extension to push messages into the outbound email queue DB, presumably
455
-bind-mounted into the container.
456
-
457
-You can do that by replacing STAGEs 2 and 3 in the stock `Dockerfile`
458
-with this:
459
-
460
-```
461
- ## ---------------------------------------------------------------------
462
- ## STAGE 2: Pare that back to the bare essentials, plus Tcl.
463
- ## ---------------------------------------------------------------------
464
- FROM alpine AS run
465
- ARG UID=499
466
- ENV PATH "/sbin:/usr/sbin:/bin:/usr/bin"
467
- COPY --from=builder /tmp/fossil /bin/
468
- COPY tools/email-sender.tcl /bin/
469
- RUN set -x \
470
- && echo "fossil:x:${UID}:${UID}:User:/museum:/false" >> /etc/passwd \
471
- && echo "fossil:x:${UID}:fossil" >> /etc/group \
472
- && install -d -m 700 -o fossil -g fossil log museum \
473
- && apk add --no-cache tcl sqlite-tcl
474
-```
475
-
476
-Build it and test that it works like so:
477
-
478
-```
479
- $ make container-run &&
480
- echo 'puts [info patchlevel]' |
481
- docker exec -i $(make container-version) tclsh
482
- 8.6.12
483
-```
484
-
485
-You should remove the `PATH` override in the “RUN”
486
-stage, since it’s written for the case where everything is in `/bin`.
487
-With these additions, we need the longer `PATH` shown above to have
488
-ready access to them all.
445
+That command assumes you built it via “`make container`” and are
446
+therefore using its versioning scheme.
447
+
448
+You will likely want to remove the `PATH` override in the “RUN” stage
449
+when doing this since it’s written for the case where everything is in
450
+`/bin`, and that will no longer be the case with a more full-featured
451
+“`run`” layer. As long as the parent layer’s `PATH` value contains
452
+`/bin`, delegating to it is more likely the correct thing.
489453
490454
Another useful case to consider is that you’ve installed a [server
491455
extension](./serverext.wiki) and you need an interpreter for that
492456
script. The first option above won’t work except in the unlikely case that
493457
it’s written for one of the bare-bones script interpreters that BusyBox
@@ -534,20 +498,92 @@
534498
general purpose like Alpine + “`apk add python`”
535499
is huge: we no longer leave a package manager sitting around inside the
536500
container, waiting for some malefactor to figure out how to abuse it.
537501
538502
Beware that there’s a limit to this über-jail’s ability to save you when
539
-you go and provide a more capable OS layer like this. The container
503
+you go and provide a more capable runtime layer like this. The container
540504
layer should stop an attacker from accessing any files out on the host
541505
that you haven’t explicitly mounted into the container’s namespace, but
542506
it can’t stop them from making outbound network connections or modifying
543507
the repo DB inside the container.
544508
545509
[cgimgs]: https://github.com/chainguard-images/images/tree/main/images
546510
[distroless]: https://www.chainguard.dev/unchained/minimal-container-images-towards-a-more-secure-future
547511
[MTA]: https://en.wikipedia.org/wiki/Message_transfer_agent
548512
513
+
514
+### 5.6 <a id="alerts"></a>Email Alerts
515
+
516
+The nature of our single static binary container precludes two of the
517
+options for [sending email alerts](./alerts.md) from Fossil:
518
+
519
+* pipe to a command
520
+* SMTP relay host
521
+
522
+There is no `/usr/sbin/sendmail` inside the container, and the container
523
+cannot connect out to a TCP service on the host by default.
524
+
525
+While it is possible to get around the first lack by [elaborating the
526
+run layer](#run), to inject a full-blown Sendmail setup into the
527
+container would go against the whole idea of containerization.
528
+Forwarding an SMTP relay port into the container isn’t nearly as bad,
529
+but it’s still bending the intent behind containers out of shape.
530
+
531
+A far better option in this case is the “store emails in database”
532
+method since the containerized Fossil binary knows perfectly well how to
533
+write SQLite DB files without relying on any external code. Using the
534
+paths in the configuration recommended above, the database path should
535
+be set to something like `/museum/mail.db`. This, along with the use of
536
+[bind mounts](#bind-mount) means you can have a process running outside
537
+the container that passes the emails along to the host-side MTA.
538
+
539
+The included [`email-sender.tcl`](/file/tools/email-sender.tcl) script
540
+works reasonably well for this, though in my own usage, I had to make
541
+two changes to it:
542
+
543
+1. The shebang line at the top has to be `#!/usr/bin/tclsh` on my server.
544
+2. I parameterized the `DBFILE` variable at the top thus:
545
+
546
+ set DBFILE [lindex $argv 0]
547
+
548
+I then wanted a way to start this Tcl script on startup and keep it
549
+running, which made me reach for systemd. My server is set to allow user
550
+services to run at boot(^”Desktop” class Linuxes tend to disable that by
551
+default under the theory that you don’t want those services to run until
552
+you’ve logged into the GUI as that user. If you find yourself running
553
+into this, [enable linger
554
+mode](https://www.freedesktop.org/software/systemd/man/loginctl.html).)
555
+so I was able to create a unit file called
556
+`~/.local/share/systemd/user/[email protected]` with these contents:
557
+
558
+```
559
+ [Unit]
560
+ Description=Fossil email alert sender for %I
561
+
562
+ [Service]
563
+ WorkingDirectory=/home/fossil/museum
564
+ ExecStart=/home/fossil/bin/alert-sender %I/mail.db
565
+ Restart=always
566
+ RestartSec=3
567
+
568
+ [Install]
569
+ WantedBy=default.target
570
+```
571
+
572
+I was then able to enable email alert forwarding for select repositories
573
+after configuring them per [the docs](./alerts.md) by saying:
574
+
575
+```
576
+ $ systemctl --user daemon-reload
577
+ $ systemctl --user enable alert-sender@myproject
578
+ $ systemctl --user start alert-sender@myproject
579
+```
580
+
581
+Because this is a parameterized script and we’ve set our repository
582
+paths predictably, you can do this for as many repositories as you need
583
+to by passing their names after the “`@`” sign in the commands above.
584
+
549585
550586
## 6. <a id="light"></a>Lightweight Alternatives to Docker
551587
552588
Those afflicted with sticker shock at seeing the size of a [Docker
553589
Desktop][DD] installation — 1.65 GB here — might’ve immediately
554590
--- www/containers.md
+++ www/containers.md
@@ -440,54 +440,18 @@
440 Rebuild and redeploy to give your Fossil container a [BusyBox]-based
441 shell environment that you can get into via:
442
443 $ docker exec -it -u fossil $(make container-version) sh
444
445 (That command assumes you built it via “`make container`” and are
446 therefore using its versioning scheme.)
447
448 Another case where you might need to replace this bare-bones “`run`”
449 layer with something more functional is that you’re setting up [email
450 alerts](./alerts.md) and need some way to integrate with the host’s
451 [MTA]. There are a number of alternatives in that linked document, so
452 for the sake of discussion, we’ll say you’ve chosen [Method
453 2](./alerts.md#db), which requires a Tcl interpreter and its SQLite
454 extension to push messages into the outbound email queue DB, presumably
455 bind-mounted into the container.
456
457 You can do that by replacing STAGEs 2 and 3 in the stock `Dockerfile`
458 with this:
459
460 ```
461 ## ---------------------------------------------------------------------
462 ## STAGE 2: Pare that back to the bare essentials, plus Tcl.
463 ## ---------------------------------------------------------------------
464 FROM alpine AS run
465 ARG UID=499
466 ENV PATH "/sbin:/usr/sbin:/bin:/usr/bin"
467 COPY --from=builder /tmp/fossil /bin/
468 COPY tools/email-sender.tcl /bin/
469 RUN set -x \
470 && echo "fossil:x:${UID}:${UID}:User:/museum:/false" >> /etc/passwd \
471 && echo "fossil:x:${UID}:fossil" >> /etc/group \
472 && install -d -m 700 -o fossil -g fossil log museum \
473 && apk add --no-cache tcl sqlite-tcl
474 ```
475
476 Build it and test that it works like so:
477
478 ```
479 $ make container-run &&
480 echo 'puts [info patchlevel]' |
481 docker exec -i $(make container-version) tclsh
482 8.6.12
483 ```
484
485 You should remove the `PATH` override in the “RUN”
486 stage, since it’s written for the case where everything is in `/bin`.
487 With these additions, we need the longer `PATH` shown above to have
488 ready access to them all.
489
490 Another useful case to consider is that you’ve installed a [server
491 extension](./serverext.wiki) and you need an interpreter for that
492 script. The first option above won’t work except in the unlikely case that
493 it’s written for one of the bare-bones script interpreters that BusyBox
@@ -534,20 +498,92 @@
534 general purpose like Alpine + “`apk add python`”
535 is huge: we no longer leave a package manager sitting around inside the
536 container, waiting for some malefactor to figure out how to abuse it.
537
538 Beware that there’s a limit to this über-jail’s ability to save you when
539 you go and provide a more capable OS layer like this. The container
540 layer should stop an attacker from accessing any files out on the host
541 that you haven’t explicitly mounted into the container’s namespace, but
542 it can’t stop them from making outbound network connections or modifying
543 the repo DB inside the container.
544
545 [cgimgs]: https://github.com/chainguard-images/images/tree/main/images
546 [distroless]: https://www.chainguard.dev/unchained/minimal-container-images-towards-a-more-secure-future
547 [MTA]: https://en.wikipedia.org/wiki/Message_transfer_agent
548
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
549
550 ## 6. <a id="light"></a>Lightweight Alternatives to Docker
551
552 Those afflicted with sticker shock at seeing the size of a [Docker
553 Desktop][DD] installation — 1.65 GB here — might’ve immediately
554
--- www/containers.md
+++ www/containers.md
@@ -440,54 +440,18 @@
440 Rebuild and redeploy to give your Fossil container a [BusyBox]-based
441 shell environment that you can get into via:
442
443 $ docker exec -it -u fossil $(make container-version) sh
444
445 That command assumes you built it via “`make container`” and are
446 therefore using its versioning scheme.
447
448 You will likely want to remove the `PATH` override in the “RUN” stage
449 when doing this since it’s written for the case where everything is in
450 `/bin`, and that will no longer be the case with a more full-featured
451 “`run`” layer. As long as the parent layer’s `PATH` value contains
452 `/bin`, delegating to it is more likely the correct thing.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
453
454 Another useful case to consider is that you’ve installed a [server
455 extension](./serverext.wiki) and you need an interpreter for that
456 script. The first option above won’t work except in the unlikely case that
457 it’s written for one of the bare-bones script interpreters that BusyBox
@@ -534,20 +498,92 @@
498 general purpose like Alpine + “`apk add python`”
499 is huge: we no longer leave a package manager sitting around inside the
500 container, waiting for some malefactor to figure out how to abuse it.
501
502 Beware that there’s a limit to this über-jail’s ability to save you when
503 you go and provide a more capable runtime layer like this. The container
504 layer should stop an attacker from accessing any files out on the host
505 that you haven’t explicitly mounted into the container’s namespace, but
506 it can’t stop them from making outbound network connections or modifying
507 the repo DB inside the container.
508
509 [cgimgs]: https://github.com/chainguard-images/images/tree/main/images
510 [distroless]: https://www.chainguard.dev/unchained/minimal-container-images-towards-a-more-secure-future
511 [MTA]: https://en.wikipedia.org/wiki/Message_transfer_agent
512
513
514 ### 5.6 <a id="alerts"></a>Email Alerts
515
516 The nature of our single static binary container precludes two of the
517 options for [sending email alerts](./alerts.md) from Fossil:
518
519 * pipe to a command
520 * SMTP relay host
521
522 There is no `/usr/sbin/sendmail` inside the container, and the container
523 cannot connect out to a TCP service on the host by default.
524
525 While it is possible to get around the first lack by [elaborating the
526 run layer](#run), to inject a full-blown Sendmail setup into the
527 container would go against the whole idea of containerization.
528 Forwarding an SMTP relay port into the container isn’t nearly as bad,
529 but it’s still bending the intent behind containers out of shape.
530
531 A far better option in this case is the “store emails in database”
532 method since the containerized Fossil binary knows perfectly well how to
533 write SQLite DB files without relying on any external code. Using the
534 paths in the configuration recommended above, the database path should
535 be set to something like `/museum/mail.db`. This, along with the use of
536 [bind mounts](#bind-mount) means you can have a process running outside
537 the container that passes the emails along to the host-side MTA.
538
539 The included [`email-sender.tcl`](/file/tools/email-sender.tcl) script
540 works reasonably well for this, though in my own usage, I had to make
541 two changes to it:
542
543 1. The shebang line at the top has to be `#!/usr/bin/tclsh` on my server.
544 2. I parameterized the `DBFILE` variable at the top thus:
545
546 set DBFILE [lindex $argv 0]
547
548 I then wanted a way to start this Tcl script on startup and keep it
549 running, which made me reach for systemd. My server is set to allow user
550 services to run at boot(^”Desktop” class Linuxes tend to disable that by
551 default under the theory that you don’t want those services to run until
552 you’ve logged into the GUI as that user. If you find yourself running
553 into this, [enable linger
554 mode](https://www.freedesktop.org/software/systemd/man/loginctl.html).)
555 so I was able to create a unit file called
556 `~/.local/share/systemd/user/[email protected]` with these contents:
557
558 ```
559 [Unit]
560 Description=Fossil email alert sender for %I
561
562 [Service]
563 WorkingDirectory=/home/fossil/museum
564 ExecStart=/home/fossil/bin/alert-sender %I/mail.db
565 Restart=always
566 RestartSec=3
567
568 [Install]
569 WantedBy=default.target
570 ```
571
572 I was then able to enable email alert forwarding for select repositories
573 after configuring them per [the docs](./alerts.md) by saying:
574
575 ```
576 $ systemctl --user daemon-reload
577 $ systemctl --user enable alert-sender@myproject
578 $ systemctl --user start alert-sender@myproject
579 ```
580
581 Because this is a parameterized script and we’ve set our repository
582 paths predictably, you can do this for as many repositories as you need
583 to by passing their names after the “`@`” sign in the commands above.
584
585
586 ## 6. <a id="light"></a>Lightweight Alternatives to Docker
587
588 Those afflicted with sticker shock at seeing the size of a [Docker
589 Desktop][DD] installation — 1.65 GB here — might’ve immediately
590

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button