This commit is contained in:
Shelvacu
2025-04-19 13:17:36 -07:00
committed by Shelvacu on fw
parent 086a258c92
commit 9bad53f188
28 changed files with 859 additions and 628 deletions

View File

@@ -257,7 +257,11 @@ else
publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJJk3a190w/1TZkzVKORvz/kwyKmFY144lVeDFm80p17";
};
"rsync.net" = {
extraHostNames = [ "rsn" "rsyncnet" "fm2382.rsync.net" ];
extraHostNames = [
"rsn"
"rsyncnet"
"fm2382.rsync.net"
];
publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINdUkGe6kKn5ssz4WRZKjcws0InbQqZayenzk9obmP1z";
};

View File

@@ -87,7 +87,10 @@ lib.mkMerge [
})
{
vacu.packages.ffmpeg-vacu-full.enable = config.vacu.systemKind == "desktop";
vacu.packages.ffmpeg-vacu-headless.enable = config.vacu.systemKind != "minimal" && config.vacu.systemKind != "container" && config.vacu.systemKind != "desktop";
vacu.packages.ffmpeg-vacu-headless.enable =
config.vacu.systemKind != "minimal"
&& config.vacu.systemKind != "container"
&& config.vacu.systemKind != "desktop";
}
{
vacu.packages = {
@@ -122,8 +125,7 @@ lib.mkMerge [
};
}
{
vacu.packages =
with pkgs; [
vacu.packages = with pkgs; [
bash
bzip2
curl

View File

@@ -33,7 +33,8 @@ let
readOnly = true;
};
};
config.finalPackage = if config.overrides == null then config.package else config.package.override config.overrides;
config.finalPackage =
if config.overrides == null then config.package else config.package.override config.overrides;
}
)
);

View File

@@ -47,7 +47,9 @@ in
};
config =
{
vacu.sourceTree = inputsOf inputs.self // { inherit inputs; };
vacu.sourceTree = inputsOf inputs.self // {
inherit inputs;
};
# vacu.sourceTree = pkgs.runCommand "inputs-tree" { } ''
# mkdir -p $out
# ln -s ${inputs.self} $out/self

View File

@@ -1,8 +1,4 @@
{
pkgs,
inputs,
...
}:
{ pkgs, inputs, ... }:
{
imports = [
inputs.jovian.nixosModules.jovian

View File

@@ -175,7 +175,8 @@
map (name: lib.nameValuePair name inputs.${name + suffix}) inp'
);
in
thisInputsA // {
thisInputsA
// {
inherit nixpkgs;
inherit (inputs) self;
};
@@ -210,7 +211,12 @@
);
lib = {
inherit mkPlain mkPkgs mkInputs mkNixosConfig;
inherit
mkPlain
mkPkgs
mkInputs
mkNixosConfig
;
};
nixosConfigurations = {
@@ -268,9 +274,7 @@
inherit (inputs) dns;
vacuModuleType = "nix-on-droid";
};
pkgs = mkPkgs {
system = arm;
};
pkgs = mkPkgs { system = arm; };
};
checks = nixpkgs.lib.genAttrs [ x86 ] (
@@ -286,15 +290,15 @@
node.specialArgs.selfPackages = self.packages.${system};
node.specialArgs.vacuModuleType = "nixos";
};
mkTest = name:
mkTest =
name:
nixpkgs.lib.nixos.runTest {
imports = [
commonTestModule
./tests/${name}
{ node.specialArgs.inputs = self.nixosConfigurations.${name}._module.specialArgs.inputs; }
];
}
;
};
checksFromConfig = plain.config.vacu.checks;
in
assert !(checksFromConfig ? liam) && !(checksFromConfig ? trip);
@@ -421,7 +425,8 @@
// (inputs.flake-utils.lib.eachDefaultSystem (
system:
let
mkNixvim = unstable:
mkNixvim =
unstable:
let
nixvim-input = if unstable then inputs.nixvim-unstable else inputs.nixvim;
in
@@ -437,12 +442,8 @@
config.allowUnfree = true;
overlays = [ inputs.sm64baserom.overlays.default ];
};
pkgs-unstable = mkPkgs (nixpkgs-args // {
useUnstable = true;
});
pkgs-stable = mkPkgs (nixpkgs-args // {
useUnstable = false;
});
pkgs-unstable = mkPkgs (nixpkgs-args // { useUnstable = true; });
pkgs-stable = mkPkgs (nixpkgs-args // { useUnstable = false; });
_plain = mkPlain pkgs-unstable;
plain = _plain.config.vacu.withAsserts _plain;
treefmtEval = inputs.treefmt-nix.lib.evalModule pkgs-unstable ./treefmt.nix;
@@ -473,14 +474,18 @@
};
generated = pkgs.linkFarm "generated" {
nixpkgs = "${inputs.nixpkgs}";
"liam-test/hints.py" = pkgs.writeText "hints.py" (import ./typesForTest.nix {
"liam-test/hints.py" = pkgs.writeText "hints.py" (
import ./typesForTest.nix {
name = "liam";
inherit (pkgs-stable) lib;
inherit self;
inherit (inputs) nixpkgs;
});
}
);
"dns/python-env" = builtins.dirOf (builtins.dirOf dns.interpreter);
"mailtest/python-env" = builtins.dirOf (builtins.dirOf self.checks.x86_64-linux.liam.nodes.checker.vacu.mailtest.smtp.interpreter);
"mailtest/python-env" = builtins.dirOf (
builtins.dirOf self.checks.x86_64-linux.liam.nodes.checker.vacu.mailtest.smtp.interpreter
);
};
haproxy-auth-request = pkgs.callPackage ./packages/haproxy-auth-request.nix {
inherit haproxy-lua-http;

View File

@@ -1,8 +1,11 @@
{ config, ... }:
{
vacu.packages = [ "tpm-fido" ];
users.groups.uhid = {};
users.users.shelvacu.extraGroups = [ config.security.tpm2.tssGroup config.users.groups.uhid.name ];
users.groups.uhid = { };
users.users.shelvacu.extraGroups = [
config.security.tpm2.tssGroup
config.users.groups.uhid.name
];
security.tpm2.enable = true;
security.tpm2.applyUdevRules = true;
services.udev.extraRules = ''

View File

@@ -13,8 +13,9 @@
background: #eee;
padding: 0 10px;
}
h1,h2,h3 { line-height: 1.2; }
h1, h2, h3 {
line-height: 1.2;
}
form {
padding: 5px;
@@ -22,21 +23,34 @@
border-radius: 3px;
margin: 5px;
}
form label { display: block; }
form label {
display: block;
}
</style>
</head>
<body>
<h1>Jobs info</h1>
<p>Hi! I am currently looking to find a Software Engineering job. I am a professional developer specializing in Ruby on Rails and Rust, with over 10 years of experience.</p>
<p>
Hi! I am currently looking to find a Software Engineering job. I am a
professional developer specializing in Ruby on Rails and Rust, with over
10 years of experience.
</p>
<p>
What I want in a job:
<ul>
<li><b>Fully Remote</b> - that means 1 visit to an office per month or less. Strongly preferred; non-remote jobs will have to be very tempting in every other category.</li>
<li>
<b>Fully Remote</b> - that means 1 visit to an office per month or
less. Strongly preferred; non-remote jobs will have to be very
tempting in every other category.
</li>
<li>Prefer direct hire, but not required.</li>
<li>W2 employment preferred, but also open to C2C/1099.</li>
<li>While I could be productive in nearly any language, I would most like to work with Rust.</li>
<li>
While I could be productive in nearly any language, I would most like
to work with Rust.
</li>
</ul>
</p>
@@ -44,41 +58,78 @@
Things you probably want to know:
<ul>
<li>I am a US citizen (USC), for work authorization purposes I can work anywhere in the US.</li>
<li>
I am a US citizen (USC), for work authorization purposes I can work
anywhere in the US.
</li>
<li>Open to both contract and permanent positions.</li>
<li>I can start within a week.</li>
<li>I do not have a formal degree, but more than enough experience to make up for it.</li>
<li>
I do not have a formal degree, but more than enough experience to make
up for it.
</li>
</ul>
</p>
<h2>Resume</h2>
<p>
<a href="/shelvacu-resume.pdf">You can see my latest, up-to-date resume here</a>.
<a href="/shelvacu-resume.pdf"
>You can see my latest, up-to-date resume here</a>.
</p>
<h2>To send me job offers</h2>
<p>Unfortunately I get a lot of bad job offers if I just give out my email to anyone. As such, I will only accept job offers sent using this form.</b>
<p>
Unfortunately I get a lot of bad job offers if I just give out my email to
anyone. As such, I will only accept job offers sent using this form.
</p>
<p>Each time you want to send me an email about a new job offer, you must return to this page. The process may change from time to time. If you have multiple jobs you think I am a good fit for, please combine them in one email.</p>
<p>
Each time you want to send me an email about a new job offer, you must
return to this page. The process may change from time to time. If you have
multiple jobs you think I am a good fit for, please combine them in one
email.
</p>
<form method="get" action="/email">
<label>
<input type="checkbox" name="confirm_fully_remote_or_exceptional" value="yes" required>
<span>This is a fully remote job, or you will give an exceptional reason why the offer should be considered despite not being fully remote.</span>
<input
type="checkbox"
name="confirm_fully_remote_or_exceptional"
value="yes"
required
>
<span>This is a fully remote job, or you will give an exceptional reason
why the offer should be considered despite not being fully
remote.</span>
</label>
<label>
<input type="checkbox" name="confirm_i_read_the_above" value="yes" required>
<span>You have read the above and will not ask about work authorization status, earliest date to start, or formal education because you already have that information.</span>
<input
type="checkbox"
name="confirm_i_read_the_above"
value="yes"
required
>
<span>You have read the above and will not ask about work authorization
status, earliest date to start, or formal education because you
already have that information.</span>
</label>
<label>
<input type="checkbox" name="confirm_include_pay" value="yes" required>
<span>You will include an estimated pay range. No "depends on experience", my resume clearly shows how much experience I have.</span>
<span>You will include an estimated pay range. No "depends on
experience", my resume clearly shows how much experience I
have.</span>
</label>
<label>
<input type="checkbox" name="confirm_no_ask_resume" value="yes" required>
<span>You will not ask for an updated resume. The latest resume is always available on this page.</span>
<input
type="checkbox"
name="confirm_no_ask_resume"
value="yes"
required
>
<span>You will not ask for an updated resume. The latest resume is
always available on this page.</span>
</label>
<label>
<div>Your email:</div>
@@ -87,6 +138,10 @@
<button type="submit">Submit</button>
</form>
<p>I apologize for the hassle. I promise that if you follow everything here before sending a job offer to me, I <i>will</i> respond, and I will make every effort to respond within 1 week.</p>
<p>
I apologize for the hassle. I promise that if you follow everything here
before sending a job offer to me, I <i>will</i> respond, and I will make
every effort to respond within 1 week.
</p>
</body>
</html>

View File

@@ -57,16 +57,20 @@ in
repo = mkOption { default = "${cfg.rsyncUser}@${cfg.rsyncHost}:borg-repos/liam-backup"; };
package = mkOption { default = pkgs.borgbackup; };
cmd = mkOption { default = lib.getExe cfg.package; };
paths = mkOption { default = [
paths = mkOption {
default = [
"/var/lib/mail"
"/var/lib/dovecot"
"/var/log"
]; };
];
};
keyPath = mkOption { default = config.sops.secrets.liam-borg-key.path; };
};
config = {
vacu.assertions = lib.singleton {
assertion = (lib.versionAtLeast cfg.package.version "1.4.0") && !(lib.versionAtLeast cfg.package.version "1.5.0");
assertion =
(lib.versionAtLeast cfg.package.version "1.4.0")
&& !(lib.versionAtLeast cfg.package.version "1.5.0");
message = "Only for version 1.4.x";
fatal = true;
};
@@ -88,7 +92,7 @@ in
group = cfg.user;
home = "/var/lib/auto-borg";
};
users.groups.${cfg.user} = {};
users.groups.${cfg.user} = { };
systemd.services.auto-borg-gen-key = {
script = ''
set -euo pipefail

View File

@@ -5,7 +5,17 @@
...
}:
let
inherit (builtins) isString isList length head all isInt isAttrs isFloat isBool;
inherit (builtins)
isString
isList
length
head
all
isInt
isAttrs
isFloat
isBool
;
inherit (lib)
concatStrings
concatStringsSep
@@ -16,21 +26,13 @@ let
elemAt
mapAttrsToList
;
mapConcat = f: xs:
concatStrings (map f xs)
;
mapConcatSep = sep: f: xs:
concatStringsSep sep (map f xs)
;
mapConcatLines = f: xs:
mapConcatSep "\n" f xs
;
isListWhere = xs: f:
(isList xs) && (all f xs)
;
stringOrList = val: (isString val) || (
(isListWhere val isString) && (length val) > 0
);
mapConcat = f: xs: concatStrings (map f xs);
mapConcatSep =
sep: f: xs:
concatStringsSep sep (map f xs);
mapConcatLines = f: xs: mapConcatSep "\n" f xs;
isListWhere = xs: f: (isList xs) && (all f xs);
stringOrList = val: (isString val) || ((isListWhere val isString) && (length val) > 0);
listify = val: if isList val then val else [ val ];
email_folders = [
"24nm-domain@shelvacu.com"
@@ -89,36 +91,47 @@ let
is_match = regex: s: (match regex s) != null;
is_not_match = regex: s: !(is_match regex s);
only_printable_ascii = s: is_match "[ -~\r\n]*" s;
has_vars = s: lib.hasInfix ("$"+"{") s;
has_vars = s: lib.hasInfix ("$" + "{") s;
# is_quoteable = s: (only_printable_ascii s) && (!lib.hasInfix ("$" + "{") s);
sieve_raw_escape_string =
s:
if !only_printable_ascii s then
builtins.trace s
throw "s failed only_printable_ascii check"
builtins.trace s throw "s failed only_printable_ascii check"
else
replaceStrings [ ''"'' ''\'' "\n" "\r" ] [ ''\"'' ''\\'' ''\n'' ''\r'' ] s
;
replaceStrings [ ''"'' ''\'' "\n" "\r" ] [ ''\"'' ''\\'' ''\n'' ''\r'' ] s;
sieve_encode_string =
{ allow_vars, for_debug_comment, with_quotes }: s:
{
allow_vars,
for_debug_comment,
with_quotes,
}:
s:
assert isString s;
assert allow_vars || for_debug_comment || (!has_vars s);
let
a = sieve_raw_escape_string s;
b = if for_debug_comment then replaceStrings [ ''*/'' ] [ ''*\/'' ] a else a;
res = if with_quotes then ''"${b}"'' else b;
in res
;
sieve_quote_string = sieve_encode_string { allow_vars = false; for_debug_comment = false; with_quotes = true; };
sieve_quote_string_with_interp = sieve_encode_string { allow_vars = true; for_debug_comment = false; with_quotes = true; };
in
res;
sieve_quote_string = sieve_encode_string {
allow_vars = false;
for_debug_comment = false;
with_quotes = true;
};
sieve_quote_string_with_interp = sieve_encode_string {
allow_vars = true;
for_debug_comment = false;
with_quotes = true;
};
is_valid_long_ident = is_match "[a-z_][a-z0-9_]*";
is_number_ident = is_match "[0-9]*";
is_valid_ident = s: (is_valid_long_ident s) || (is_number_ident s);
interp = ident:
interp =
ident:
assert isString ident;
assert is_valid_ident ident;
"$" + "{${ident}}"
;
"$" + "{${ident}}";
dest = "envelope_to";
dest_domain = "envelope_to_domain";
set_envelope = ''
@@ -133,35 +146,51 @@ let
'';
envelope_is = key: ''string :is "${interp dest}" ${sieve_quote_string key}'';
envelope_domain_is = key: ''string :is "${interp dest_domain}" ${sieve_quote_string key}'';
sieve_encode_list = xs:
sieve_encode_list =
xs:
assert isListWhere xs isString;
"[ ${mapConcatSep ", " sieve_encode xs} ]"
;
sieve_encode = val:
if isString val then sieve_quote_string val
else if isList val then sieve_encode_list val
else assert "dunno what to do with this"; null
;
"[ ${mapConcatSep ", " sieve_encode xs} ]";
sieve_encode =
val:
if isString val then
sieve_quote_string val
else if isList val then
sieve_encode_list val
else
assert "dunno what to do with this";
null;
sieve_debug_list = xs: "[ ${mapConcat (s: (sieve_debug s) + " ") xs}]";
sieve_debug_attrs = attrs:
sieve_debug_attrs =
attrs:
let
toPairStr = name: val: "${sieve_debug name} = ${sieve_debug val}; ";
pairStrs = mapAttrsToList toPairStr attrs;
pairsStr = concatStrings pairStrs;
in
"{ ${pairsStr}}"
;
sieve_debug = val:
if isString val then sieve_encode_string { allow_vars = true; for_debug_comment = true; with_quotes = true; } val
else if (isInt val) || (isFloat val) then toString val
"{ ${pairsStr}}";
sieve_debug =
val:
if isString val then
sieve_encode_string {
allow_vars = true;
for_debug_comment = true;
with_quotes = true;
} val
else if (isInt val) || (isFloat val) then
toString val
else if (isBool val) then
(if val then "true" else "false")
else if isNull val then "null"
else if isList val then sieve_debug_list val
else if isAttrs val then sieve_debug_attrs val
else assert "dunno what to do with this"; null
;
pure_flags_impl = flags: conditions:
else if isNull val then
"null"
else if isList val then
sieve_debug_list val
else if isAttrs val then
sieve_debug_attrs val
else
assert "dunno what to do with this";
null;
pure_flags_impl =
flags: conditions:
assert isListWhere flags isString;
assert isListWhere conditions isString;
assert (length flags) > 0;
@@ -180,92 +209,92 @@ let
}
# pure_flags end
'';
pure_flags = flags: conditions:
pure_flags =
flags: conditions:
assert stringOrList flags;
assert stringOrList conditions;
pure_flags_impl (listify flags) (listify conditions)
;
exists_impl = headers:
pure_flags_impl (listify flags) (listify conditions);
exists_impl =
headers:
assert isListWhere headers isString;
if headers == [] then
if headers == [ ] then
"/* exists START: called with empty array */ false /* exists END */"
else
"/* exists START */ exists ${sieve_encode_list headers} /* exists END */"
;
exists = headers:
"/* exists START */ exists ${sieve_encode_list headers} /* exists END */";
exists =
headers:
assert stringOrList headers;
exists_impl (listify headers)
;
header_generic = match_kind: header_s: match_es:
exists_impl (listify headers);
header_generic =
match_kind: header_s: match_es:
assert stringOrList header_s;
assert stringOrList match_es;
''/* header_generic START */ header ${match_kind} ${sieve_encode header_s} ${sieve_encode match_es} /* header_generic END */''
;
''/* header_generic START */ header ${match_kind} ${sieve_encode header_s} ${sieve_encode match_es} /* header_generic END */'';
header_matches = header_generic ":matches";
header_is = header_generic ":is";
subject_generic = match_kind: match_es: header_generic match_kind "Subject" match_es;
subject_matches = subject_generic ":matches";
subject_is = subject_generic ":is";
environment_generic = match_kind: environment_name_s: match_es:
environment_generic =
match_kind: environment_name_s: match_es:
assert stringOrList environment_name_s;
assert stringOrList match_es;
"environment ${match_kind} ${sieve_encode environment_name_s} ${sieve_encode match_es}"
;
"environment ${match_kind} ${sieve_encode environment_name_s} ${sieve_encode match_es}";
environment_matches = environment_generic ":matches";
environment_is = environment_generic ":is";
from_is = addr_list:
from_is =
addr_list:
assert stringOrList addr_list;
''/* from_is START */ address :is :all "From" ${sieve_encode addr_list} /* from_is END */''
;
var_is = var_name: rhs:
''/* from_is START */ address :is :all "From" ${sieve_encode addr_list} /* from_is END */'';
var_is =
var_name: rhs:
assert isString var_name;
assert stringOrList rhs;
''string :is "''${${var_name}}" ${sieve_encode rhs}''
;
''string :is "''${${var_name}}" ${sieve_encode rhs}'';
var_is_true = var_name: var_is var_name "1";
var_is_false = var_name: not (var_is_true var_name);
set_with_interp = var_name: new_val:
set_with_interp =
var_name: new_val:
assert isString var_name;
assert is_valid_ident var_name;
assert isString new_val;
"set ${sieve_encode var_name} ${sieve_quote_string_with_interp new_val};"
;
set = var_name: new_val:
"set ${sieve_encode var_name} ${sieve_quote_string_with_interp new_val};";
set =
var_name: new_val:
assert isString var_name;
assert is_valid_ident var_name;
assert isString new_val;
"set ${sieve_encode var_name} ${sieve_encode new_val};"
;
set_bool_var = var_name: bool_val:
"set ${sieve_encode var_name} ${sieve_encode new_val};";
set_bool_var =
var_name: bool_val:
assert isBool bool_val;
set var_name (if bool_val then "1" else "0")
;
over_test_list = name: test_list:
set var_name (if bool_val then "1" else "0");
over_test_list =
name: test_list:
assert isListWhere test_list isString;
''
${name}(
${concatStringsSep ",\n" test_list}
)
''
;
'';
anyof = over_test_list "anyof";
allof = over_test_list "allof";
not = test: "not ${test}";
record_action = action_desc:
record_action =
action_desc:
assert isString action_desc;
''addheader "X-Vacu-Action" ${sieve_encode action_desc};''
;
fileinto = folder:
''addheader "X-Vacu-Action" ${sieve_encode action_desc};'';
fileinto =
folder:
assert isString folder;
''
${record_action "fileinto ${folder}"}
fileinto :create ${sieve_encode folder};
''
;
ihave = extension_name_s:
'';
ihave =
extension_name_s:
assert stringOrList extension_name_s;
"ihave ${sieve_encode extension_name_s}"
;
"ihave ${sieve_encode extension_name_s}";
email_filters = map (e: ''
elsif ${envelope_is e} { # item of email_filters
${record_action "email_filters fileinto ${mk_email_folder_name e}"}
@@ -291,7 +320,9 @@ let
${set_with_interp var (interp "1")}
}
else {
${lib.optionalString warn_if_unset (maybe_debug "info: Could not set ${var} from condition ${condition}, setting to default(${default})")}
${lib.optionalString warn_if_unset (
maybe_debug "info: Could not set ${var} from condition ${condition}, setting to default(${default})"
)}
${set var default}
}
# set_from END
@@ -305,13 +336,11 @@ let
condition = ''environment :matches ${sieve_quote_string item} "*"'';
inherit var;
};
maybe_debug = msg:
''
maybe_debug = msg: ''
if ${ihave "vnd.dovecot.debug"} {
debug_log ${sieve_quote_string_with_interp msg};
}
''
;
'';
sieve_text = ''
require [
"fileinto",
@@ -325,22 +354,33 @@ let
"ihave"
];
if ${allof [
if ${
allof [
(ihave "imapsieve")
(environment_matches "imap.user" "*")
(environment_matches "location" "MS")
(environment_matches "phase" "post")
]} {
]
} {
${set_bool_var "in_imap" true}
} else {
${set_bool_var "in_imap" false}
}
if ${var_is_true "in_imap"} {
if ${not (allof [
(environment_is "imap.cause" ["APPEND" "COPY" ""])
(environment_is "imap.mailbox" ["MagicRefilter" ""])
])} {
if ${
not (allof [
(environment_is "imap.cause" [
"APPEND"
"COPY"
""
])
(environment_is "imap.mailbox" [
"MagicRefilter"
""
])
])
} {
${maybe_debug "NOT doing anything cuz imap.cause and/or imap.mailbox isn't right"}
stop;
}
@@ -358,9 +398,7 @@ let
condition = ''currentdate :matches "iso8601" "*"'';
var = "datetime";
}}
${set_with_interp "sieved_message"
''at ''${datetime} by ${config.vacu.versionId} loc ''${env_location} phase ''${env_phase} user ''${env_imap_user} email ''${env_imap_email} cause ''${env_imap_cause} mailbox ''${env_imap_mailbox} changedflags ''${env_imap_changedflags} envelope ''${dest}''
}
${set_with_interp "sieved_message" ''at ''${datetime} by ${config.vacu.versionId} loc ''${env_location} phase ''${env_phase} user ''${env_imap_user} email ''${env_imap_email} cause ''${env_imap_cause} mailbox ''${env_imap_mailbox} changedflags ''${env_imap_changedflags} envelope ''${dest}''}
${maybe_debug ''X-Vacu-Sieved: ''${sieved_message}''}
if ${ihave "envelope"} {
@@ -382,43 +420,76 @@ let
removeflag "ignore";
removeflag "not-spamish";
${pure_flags ["amazon-ignore" "ignore"] [
${pure_flags
[ "amazon-ignore" "ignore" ]
[
(envelope_is "amznbsns@shelvacu.com")
(subject_matches [ "Your Amazon.com order has shipped*" "Your Amazon.com order of * has shipped!" ])
]}
${pure_flags ["bandcamp-ignore" "ignore"] [
(subject_matches [
"Your Amazon.com order has shipped*"
"Your Amazon.com order of * has shipped!"
])
]
}
${pure_flags
[ "bandcamp-ignore" "ignore" ]
[
(envelope_is "bandcamp@shelvacu.com")
(subject_matches [ "* just announced a listening party on Bandcamp" "New items from *" "Starting in *" "New from *" ])
]}
${pure_flags ["ika-ignore" "ignore"] (envelope_is "ika@dis8.net")}
${pure_flags ["ally-statement" "ignore"] [
(subject_matches [
"* just announced a listening party on Bandcamp"
"New items from *"
"Starting in *"
"New from *"
])
]
}
${pure_flags [ "ika-ignore" "ignore" ] (envelope_is "ika@dis8.net")}
${pure_flags
[ "ally-statement" "ignore" ]
[
(envelope_is "ally@shelvacu.com")
(subject_is "Your latest statement is ready to view.")
]}
]
}
${pure_flags "bloomberg" (envelope_is "bloomberg@shelvacu.com")}
${pure_flags ["money-stuff" "not-spamish"] [
${pure_flags
[ "money-stuff" "not-spamish" ]
[
(envelope_is "bloomberg@shelvacu.com")
''header :matches "From" "\"Matt Levine\" *"''
]}
]
}
${pure_flags ["git" "not-spamish"] (exists ["X-GitHub-Reason" "X-GitLab-Project"])}
${pure_flags ["git-uninsane" "git" "not-spamish"] (envelope_is "git-uninsane@shelvacu.com")}
${pure_flags [ "git" "not-spamish" ] (exists [
"X-GitHub-Reason"
"X-GitLab-Project"
])}
${pure_flags [ "git-uninsane" "git" "not-spamish" ] (envelope_is "git-uninsane@shelvacu.com")}
${pure_flags ["discourse" "not-spamish"] (exists "X-Discourse-Post-Id")}
${pure_flags ["agora" "not-spamish"] (envelope_is "agora@shelvacu.com")}
${pure_flags ["postgres-list" "not-spamish"] (header_matches "List-Id" "<*.lists.postgresql.org>")}
${pure_flags ["secureaccesswa" "not-spamish"] (from_is "help@secureaccess.wa.gov")}
${pure_flags ["letsencrypt-mailing-list" "not-spamish"] (envelope_is "lets-encrypt-mailing-list@shelvacu.com")}
${pure_flags ["jmp-news" "not-spamish"] (header_matches "List-Id" "*<jmp-news.soprani.ca>")}
${pure_flags ["tf2wiki" "not-spamish"] [
${pure_flags [ "discourse" "not-spamish" ] (exists "X-Discourse-Post-Id")}
${pure_flags [ "agora" "not-spamish" ] (envelope_is "agora@shelvacu.com")}
${pure_flags [ "postgres-list" "not-spamish" ] (
header_matches "List-Id" "<*.lists.postgresql.org>"
)}
${pure_flags [ "secureaccesswa" "not-spamish" ] (from_is "help@secureaccess.wa.gov")}
${pure_flags [ "letsencrypt-mailing-list" "not-spamish" ] (
envelope_is "lets-encrypt-mailing-list@shelvacu.com"
)}
${pure_flags [ "jmp-news" "not-spamish" ] (header_matches "List-Id" "*<jmp-news.soprani.ca>")}
${pure_flags
[ "tf2wiki" "not-spamish" ]
[
(envelope_is "tf2wiki@shelvacu.com")
(from_is "noreply@wiki.teamfortress.com")
]}
]
}
${pure_flags "gmail-fwd" (envelope_is "gmailfwd-fc2e10bec8b2@shelvacu.com")}
${pure_flags "aliexpress" (from_is ["transaction@notice.aliexpress.com" "aliexpress@notice.aliexpress.com"])}
${pure_flags "aliexpress" (from_is [
"transaction@notice.aliexpress.com"
"aliexpress@notice.aliexpress.com"
])}
removeflag "auto-marked-read";
if hasflag "ignore" {

View File

@@ -31,6 +31,6 @@
vacu.packages = [
"yt-dlp"
"radicle-node"
"ncurses" #want this everywhere for clear/reset commands, but its included by default in nixos so only need ta specify here
"ncurses" # want this everywhere for clear/reset commands, but its included by default in nixos so only need ta specify here
];
}

View File

@@ -1,8 +1,4 @@
{
config,
lib,
...
}:
{ config, lib, ... }:
{
imports = [ ./lean.nix ];
opts = {
@@ -23,7 +19,10 @@
lua_ls.enable = true;
nixd = {
enable = true;
cmd = [ (lib.getExe config.plugins.lsp.servers.nixd.package) "--log=error" ];
cmd = [
(lib.getExe config.plugins.lsp.servers.nixd.package)
"--log=error"
];
};
pyright.enable = true;
rust_analyzer = {

View File

@@ -9,7 +9,8 @@ let
lean = inputs.self.packages.${system}.leanLatest;
in
{
imports = []
imports =
[ ]
++ (lib.optional (!unstable) {
plugins.lean.leanPackage = lean;
plugins.lean.mappings = true;
@@ -17,7 +18,6 @@ in
++ (lib.optional unstable {
dependencies.lean.enable = false;
plugins.lean.settings.mappings = true;
})
;
});
plugins.lean.enable = true;
}

View File

@@ -8,7 +8,7 @@
git,
libdbusmenu,
# options passed to the thunderbird builder, but with betterbird defaults
# options passed to the thunderbird builder, but with betterbird defaults
privacySupport ? true,
requireSigning ? false,
allowAddonSideload ? true,
@@ -33,11 +33,14 @@ let
tag = version;
hash = "sha256-9UG1juN/vKHY3LRuryjMDdaFapd6y7ySu0Fn3GTeN2w=";
};
patchesFromThunderbird = runCommandNoCC "betterbird-patches-from-network" {
patchesFromThunderbird =
runCommandNoCC "betterbird-patches-from-network"
{
outputHashAlgo = "sha256";
outputHashMode = "recursive";
outputHash = "sha256-4OD7OckIA/qB0jI9dNk1Q6cTZZrKVufDNvPKSeEWYBY=";
} ''
}
''
set -xev
mkdir -p $out
fetchFromSeries() {
@@ -95,18 +98,18 @@ let
applySeries ${betterbirdPatches}/${majorVersion}/series $out/comm
'';
in
(thunderbird-128-unwrapped.override {
inherit privacySupport requireSigning allowAddonSideload;
}).overrideAttrs (old: rec {
(thunderbird-128-unwrapped.override { inherit privacySupport requireSigning allowAddonSideload; })
.overrideAttrs
(old: rec {
pname = "betterbird";
inherit version;
name = "${pname}-${version}";
buildInputs = (old.buildInputs or []) ++ [ libdbusmenu ];
buildInputs = (old.buildInputs or [ ]) ++ [ libdbusmenu ];
src = replacement_src;
configureFlags = (old.configureFlags or []) ++ [
configureFlags = (old.configureFlags or [ ]) ++ [
# "--enable-application=comm/mail"
"--with-branding=comm/mail/branding/betterbird"
# "--disable-updater"
@@ -119,7 +122,9 @@ in
# "--enable-official-branding"
];
preConfigure = (old.preConfigure or "") + ''
preConfigure =
(old.preConfigure or "")
+ ''
# Disable enforcing that add-ons are signed.
export MOZ_REQUIRE_SIGNING=
export MOZ_REQUIRE_ADDON_SIGNING=0
@@ -144,5 +149,13 @@ in
export MOZ_NO_PIE_COMPAT=1
'';
passthru = (old.passthru or {}) // { inherit betterbirdPatches mozilla_src comm_src replacement_src patchesFromThunderbird; };
})
passthru = (old.passthru or { }) // {
inherit
betterbirdPatches
mozilla_src
comm_src
replacement_src
patchesFromThunderbird
;
};
})

View File

@@ -1,10 +1,11 @@
# shellcheck shell=bash
translateWetransferLinks() {
local old_urlsArray=("${urls[*]}")
local new_urlsArray=()
for this_url in "${old_urlsArray[@]}"; do
if [[ "$this_url" = https://we.tl/* ]] || [[ "$this_url" = https://wetransfer.com/downloads/* ]]; then
if [[ $this_url == https://we.tl/* ]] || [[ $this_url == https://wetransfer.com/downloads/* ]]; then
local new_url
new_url="$("$transferweeBin" -v -g download "$this_url")"
new_url="$("${transferweeBin:?}" -v -g download "$this_url")"
new_urlsArray+=("$new_url")
else
new_urlsArray+=("$this_url")

View File

@@ -1,6 +1,8 @@
self: _super: {
fetchurlWithWetransfer = args: (self.fetchurl args).overrideAttrs (old: {
nativeBuildInputs = (old.nativeBuildInputs or []) ++ [ ./convert-wetransfer-links.sh ];
fetchurlWithWetransfer =
args:
(self.fetchurl args).overrideAttrs (old: {
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ ./convert-wetransfer-links.sh ];
env.transferweeBin = self.lib.getExe self.transferwee;
env.NIX_DEBUG = "6";
});

View File

@@ -1,8 +1,6 @@
{
lean4,
fetchFromGitHub,
}:
lean4.overrideAttrs (final: prev: {
{ lean4, fetchFromGitHub }:
lean4.overrideAttrs (
final: prev: {
version = "4.19.0-rc3";
src = fetchFromGitHub {
owner = "leanprover";
@@ -10,6 +8,6 @@ lean4.overrideAttrs (final: prev: {
tag = "v4.19.0-rc3";
hash = "sha256-3a+zMGr1JnjxCm9sx8ikTpPXUoaOxmO6o5I0akip+kU=";
};
cmakeFlags = (prev.cmakeFlags or []) ++ [ "-DUSE_MIMALLOC=OFF" ];
})
cmakeFlags = (prev.cmakeFlags or [ ]) ++ [ "-DUSE_MIMALLOC=OFF" ];
}
)

View File

@@ -17,8 +17,9 @@ let
];
python = pkgs.python312.withPackages (_: libraries);
in
(pkgs.writers.writePython3Bin "dns-update" {
inherit libraries;
} pythonScript).overrideAttrs (old: {
passthru = (old.passthru or {}) // { inherit libraries python; };
})
(pkgs.writers.writePython3Bin "dns-update" { inherit libraries; } pythonScript).overrideAttrs
(old: {
passthru = (old.passthru or { }) // {
inherit libraries python;
};
})

View File

@@ -71,7 +71,8 @@ let
mkdir -p $out/liam
SOPS_AGE_KEY="${testAgeSecret}" ${pkgs.sops}/bin/sops --verbose -e --age "$(echo "${testAgeSecret}" | ${pkgs.age}/bin/age-keygen -y)" ${sopsTestSecretsYaml} --output-type yaml > $out/liam/main.yaml
'';
mailtestModule = {
mailtestModule =
{
config,
pkgs,
lib,
@@ -82,7 +83,9 @@ let
imap-tools
requests
];
mkPkg = name: pkgs.writers.writePython3Bin "mailtest-${name}" { inherit libraries; } ''
mkPkg =
name:
pkgs.writers.writePython3Bin "mailtest-${name}" { inherit libraries; } ''
# flake8: noqa
${builtins.readFile ./mailtest/${name}.py}
'';
@@ -168,7 +171,12 @@ in
};
nodes.liam =
{ lib, inputs, config, ... }:
{
lib,
inputs,
config,
...
}:
{
imports = [
"${inputs.self}/common"
@@ -209,8 +217,10 @@ in
security.pki.certificateFiles = [ rootCA.certificatePath ];
vacu.liam.backup.keyPath = pkgs.writeText "test-borg-key" testBorgKey;
vacu.ssh.knownHosts."rsync.net".enable = lib.mkForce false; #remove known key so i can do a trust-on-first-use in the test
networking.hosts."${nodes.rsyncnet.networking.primaryIPAddress}" = [ config.vacu.liam.backup.rsyncHost ];
vacu.ssh.knownHosts."rsync.net".enable = lib.mkForce false; # remove known key so i can do a trust-on-first-use in the test
networking.hosts."${nodes.rsyncnet.networking.primaryIPAddress}" = [
config.vacu.liam.backup.rsyncHost
];
};
nodes.rsyncnet =
@@ -218,7 +228,7 @@ in
let
borgCfg = nodes.liam.vacu.liam.backup;
user = borgCfg.rsyncUser;
loginCommand = pkgs.writers.writeBashBin "special-rsync-login" {} ''
loginCommand = pkgs.writers.writeBashBin "special-rsync-login" { } ''
set -euo pipefail
if [ -n "$SSH_ORIGINAL_COMMAND" ]; then
echo "hi there"
@@ -255,7 +265,7 @@ in
};
environment.systemPackages = [
pkgs.borgbackup
(pkgs.writers.writeBashBin "borg-init" {} ''
(pkgs.writers.writeBashBin "borg-init" { } ''
set -euo pipefail
export BORG_PASSPHRASE=${lib.escapeShellArg testBorgKey}
export BORG_NEW_PASSPHRASE=${lib.escapeShellArg testBorgKey}
@@ -268,9 +278,7 @@ in
{ pkgs, lib, ... }:
{
imports = [ mailtestModule ];
environment.systemPackages = [
pkgs.wget
];
environment.systemPackages = [ pkgs.wget ];
networking.nameservers = lib.mkForce (lib.singleton nodes.ns.networking.primaryIPAddress);
};
@@ -288,7 +296,8 @@ in
};
dataJson = builtins.toJSON data;
res = builtins.replaceStrings [ "@data@" ] [ dataJson ] rawFile;
in res;
in
res;
skipTypeCheck = true;
skipLint = true;

View File

@@ -6,18 +6,22 @@ import ssl
import json
from typing import NamedTuple
def info(msg: str):
print(msg, file=sys.stderr)
def mk_ctx():
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
return ctx
def print_json(**kwargs):
print(json.dumps(kwargs))
parser = argparse.ArgumentParser()
parser.add_argument("--host", type=str)
parser.add_argument("--insecure", default=False, action="store_true")
@@ -45,6 +49,7 @@ info(f"looking for {msg_magic}")
result: bool
matching_messages = []
try:
def connection() -> imap_tools.BaseMailBox:
return imap_tools.MailBox(args.host, ssl_context=mk_ctx()).login(
username, password
@@ -99,6 +104,7 @@ except imaplib.IMAP4.error as e:
else:
result = True
def mail_to_jsonish(m: MessageInFolder) -> dict:
return {
"folder": m.folder,
@@ -106,7 +112,8 @@ def mail_to_jsonish(m: MessageInFolder) -> dict:
"body": m.message.text.strip(),
}
print_json(
result = result,
messages = [mail_to_jsonish(m) for m in matching_messages],
result=result,
messages=[mail_to_jsonish(m) for m in matching_messages],
)

View File

@@ -3,9 +3,11 @@ import requests
import sys
import json
def info(msg: str):
print(msg, file=sys.stderr)
def print_json(**kwargs):
print(json.dumps(kwargs))
@@ -37,4 +39,4 @@ for message_data in mails["messages"]:
found_message = True
break
print_json(found_message = found_message)
print_json(found_message=found_message)

View File

@@ -4,18 +4,22 @@ import sys
import ssl
import json
def info(msg: str):
print(msg, file=sys.stderr)
def mk_ctx():
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
return ctx
def print_json(**kwargs):
print(json.dumps(kwargs))
parser = argparse.ArgumentParser()
parser.add_argument("--host", type=str)
parser.add_argument("--mailfrom", default="foo@example.com")
@@ -64,4 +68,4 @@ except smtplib.SMTPSenderRefused:
else:
result = True
print_json(result = result)
print_json(result=result)

View File

@@ -2,14 +2,17 @@ import sys
import ssl
import json
def info(msg: str):
print(msg, file=sys.stderr)
def mk_ctx():
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
return ctx
def print_json(**kwargs):
print(json.dumps(kwargs))

View File

@@ -32,7 +32,7 @@ liam.wait_for_unit("dovecot2.service")
relay.wait_for_unit("mailpit.service")
# generate and exchange keys so they can talk to eachother
rsyncnet.wait_for_open_port(22);
rsyncnet.wait_for_open_port(22)
# liam.succeed("install -d --owner=autoborger --group=autoborger --mode=0770 /var/lib/auto-borg")
# # not succeed, it will fail because not authorized but that's okay
# liam.execute("sudo -u autoborger ssh -oBatchMode=yes -oStrictHostKeyChecking=accept-new fm2382.rsync.net")
@@ -40,7 +40,9 @@ liam.succeed("systemctl start auto-borg-gen-key.service")
# liam.wait_for_unit("auto-borg-gen-key.service")
liam_autoborger_key = liam.succeed("cat /var/lib/auto-borg/id_ed25519.pub").strip()
rsyncnet.succeed("install -d --owner=fm2382 --mode=0700 /home/fm2382/.ssh")
rsyncnet.succeed(f"install --owner=fm2382 --mode=0600 -T <(echo 'command=\"borg serve --restrict-to-repository /home/fm2382/borg-repos/liam-backup --append-only\",restrict {liam_autoborger_key}') /home/fm2382/.ssh/authorized_keys")
rsyncnet.succeed(
f"install --owner=fm2382 --mode=0600 -T <(echo 'command=\"borg serve --restrict-to-repository /home/fm2382/borg-repos/liam-backup --append-only\",restrict {liam_autoborger_key}') /home/fm2382/.ssh/authorized_keys"
)
rsyncnet.succeed("sudo -u fm2382 borg-init")
liam.succeed("systemctl start auto-borg.service")
# liam.wait_for_unit("auto-borg.service")
@@ -51,21 +53,25 @@ class ImapMessage(TypedDict):
flags: list[str]
body: str
class ImapResult(TypedDict):
result: bool
messages: list[ImapMessage]
def make_command(args: list) -> str:
return " ".join(map(shlex.quote, (map(str, args))))
Arg = str|bool|int
Arg = str | bool | int
Args = dict[str, Arg]
def dict_args_to_list(dict_args: Args) -> list[str]:
args:list[str] = []
args: list[str] = []
for k, v in dict_args.items():
dashed = k.replace("_","-")
dashed = k.replace("_", "-")
if isinstance(v, int) and not isinstance(v, bool):
v = str(v)
if isinstance(v, str) or (isinstance(v, bool) and v):
@@ -74,12 +80,14 @@ def dict_args_to_list(dict_args: Args) -> list[str]:
args.append(v)
return args
class LogEntry(TypedDict):
__CURSOR: str
_SYSTEMD_UNIT: str
MESSAGE: str
pass
DEFAULT_JOURNALCTL_OPTS: Args = {
"all": True,
"output": "json",
@@ -94,22 +102,27 @@ DEFAULT_JOURNALCTL_OPTS: Args = {
#
# 3. Fields containing non-printable or non-UTF8 bytes are encoded as arrays containing the raw bytes individually formatted as unsigned numbers.
def journalctl_log_entries(machine: Machine = liam, **kwargs: Arg) -> Generator[LogEntry, None, None]:
def journalctl_log_entries(
machine: Machine = liam, **kwargs: Arg
) -> Generator[LogEntry, None, None]:
with_defaults = {**kwargs, **DEFAULT_JOURNALCTL_OPTS}
args = ["journalctl", *dict_args_to_list(with_defaults)]
res = machine.succeed(make_command(args))
for line in res.splitlines():
data:LogEntry = json.loads(line)
data: LogEntry = json.loads(line)
assert isinstance(data, dict)
for _, v in data.items():
assert isinstance(v, str)
yield data
class ProcessingWaiter(contextlib.AbstractContextManager):
cursor: str = ""
timeout: int = 60
_postfix_smtpd_connections: set[str] = set()
_postfix_queue: set[str] = set()
def __init__(self, timeout=60):
most_recent_entry = list(journalctl_log_entries(lines=1))[0]
self.cursor = most_recent_entry["__CURSOR"]
@@ -128,7 +141,9 @@ class ProcessingWaiter(contextlib.AbstractContextManager):
assert sl_pid is not None
if message.startswith("connect from"):
self._postfix_smtpd_connections.add(sl_pid)
if message.startswith("disconnect from") or message.startswith("lost connection"):
if message.startswith("disconnect from") or message.startswith(
"lost connection"
):
self._postfix_smtpd_connections.discard(sl_pid)
if unit == "postfix.service" and sl_ident == "postfix/qmgr":
queue_id = message.split(":")[0]
@@ -136,7 +151,10 @@ class ProcessingWaiter(contextlib.AbstractContextManager):
self._postfix_queue.add(queue_id)
if message.endswith("removed"):
self._postfix_queue.discard(queue_id)
if len(self._postfix_smtpd_connections) == 0 and len(self._postfix_queue) == 0:
if (
len(self._postfix_smtpd_connections) == 0
and len(self._postfix_queue) == 0
):
return
else:
liam.sleep(1)
@@ -144,32 +162,28 @@ class ProcessingWaiter(contextlib.AbstractContextManager):
def __exit__(self, _a, _b, _c):
self.wait_until_finished()
class TesterThing():
class TesterThing:
uuid: str = ""
default_smtp: Args = {}
default_imap: Args = {}
default_mailpit: Args = {}
def __init__(self, smtp: Args = {}, imap: Args = {}, mailpit: Args = {}, **common: Arg):
def __init__(
self, smtp: Args = {}, imap: Args = {}, mailpit: Args = {}, **common: Arg
):
self.uuid = str(uuid.uuid4())
self.default_smtp = {
"rcptto": "someone@example.com",
"host": f"{liam_ip}",
**common,
**smtp
}
self.default_imap = {
"host": f"{liam_ip}",
**common,
**imap
}
self.default_mailpit = {
"mailpit-url": f"http://{relay_ip}:8025",
**mailpit
**smtp,
}
self.default_imap = {"host": f"{liam_ip}", **common, **imap}
self.default_mailpit = {"mailpit-url": f"http://{relay_ip}:8025", **mailpit}
def run_expecting_json(self, name: str, **kwargs: Arg) -> dict[str, Any]:
args:list[str] = [name, *dict_args_to_list(kwargs)]
args: list[str] = [name, *dict_args_to_list(kwargs)]
print(f"running {args!r}")
with ProcessingWaiter():
res = checker.succeed(make_command(args))
@@ -198,32 +212,34 @@ class TesterThing():
res_ty: ImapResult = res_unty # type: ignore
return res_ty
def imap_expect(self, mailbox: str|None = None, flags: list[str] = [], **kwargs: Arg) -> Self:
def imap_expect(
self, mailbox: str | None = None, flags: list[str] = [], **kwargs: Arg
) -> Self:
res = self.run_imap(**kwargs)
assert res['result']
assert len(res['messages']) == 1
message = res['messages'][0]
assert res["result"]
assert len(res["messages"]) == 1
message = res["messages"][0]
if mailbox is not None:
assert message['folder'] == mailbox
assert message["folder"] == mailbox
for flag in flags:
assert flag in message['flags']
assert flag in message["flags"]
return self
def imap_found(self, **kwargs: Arg) -> Self:
return self.imap_expect(mailbox = None, flags = [], **kwargs)
return self.imap_expect(mailbox=None, flags=[], **kwargs)
def imap_found_in(self, mailbox: str, **kwargs: Arg) -> Self:
return self.imap_expect(mailbox = mailbox, flags = [], **kwargs)
return self.imap_expect(mailbox=mailbox, flags=[], **kwargs)
def imap_move_to(self, dest: str, **kwargs: Arg) -> Self:
res = self.run_imap(move_to=dest, **kwargs)
assert res['result']
assert res["result"]
return self
def run_mailpit(self, **kwargs: Arg) -> bool:
args = {"message_magic": self.uuid, **self.default_mailpit, **kwargs}
res = self.run_expecting_json("mailtest-mailpit", **args)
return res['found_message']
return res["found_message"]
def mailpit_not_received(self, **kwargs: Arg) -> Self:
received = self.run_mailpit(**kwargs)
@@ -235,57 +251,78 @@ class TesterThing():
assert received
return self
class Defaults():
class Defaults:
default_smtp: Args = {}
default_imap: Args = {}
default_mailpit: Args = {}
def __init__(self, smtp: Args = {}, imap: Args = {}, mailpit: Args = {}, **common: str|bool):
self.default_smtp = {
**common,
**smtp
}
self.default_imap = {
**common,
**imap
}
self.default_mailpit = {
**mailpit
}
def __init__(
self, smtp: Args = {}, imap: Args = {}, mailpit: Args = {}, **common: str | bool
):
self.default_smtp = {**common, **smtp}
self.default_imap = {**common, **imap}
self.default_mailpit = {**mailpit}
def make_tester(self, smtp: Args = {}, imap: Args = {}, mailpit: Args = {}, **common: str|bool) -> TesterThing:
def make_tester(
self, smtp: Args = {}, imap: Args = {}, mailpit: Args = {}, **common: str | bool
) -> TesterThing:
return TesterThing(
smtp = {**self.default_smtp, **common, **smtp},
imap = {**self.default_imap, **common, **imap},
mailpit = {**self.default_mailpit, **common, **mailpit},
smtp={**self.default_smtp, **common, **smtp},
imap={**self.default_imap, **common, **imap},
mailpit={**self.default_mailpit, **common, **mailpit},
)
# The order of these shouldn't matter, other than what fails first. Whatever is at the top is probably whatever I was working on most recently.
d = Defaults(smtp = {"submission": True, "rcptto": "someone@example.com"}, username = "vacustore")
d.make_tester(smtp = {"mailfrom": "robot@vacu.store"}).smtp_accepted().mailpit_received()
d.make_tester(smtp = {"mailfrom": "foobar@vacu.store"}).smtp_rejected()
d.make_tester(smtp = {"mailfrom": "abc@shelvacu.com"}).smtp_rejected()
d = Defaults(smtp = {"mailfrom": "whoeve2@example.com", "rcptto": "sieve2est@shelvacu.com"}, username = "shelvacu")
# The order of these shouldn't matter, other than what fails first. Whatever is at the top is probably whatever I was working on most recently.
d = Defaults(
smtp={"submission": True, "rcptto": "someone@example.com"}, username="vacustore"
)
d.make_tester(smtp={"mailfrom": "robot@vacu.store"}).smtp_accepted().mailpit_received()
d.make_tester(smtp={"mailfrom": "foobar@vacu.store"}).smtp_rejected()
d.make_tester(smtp={"mailfrom": "abc@shelvacu.com"}).smtp_rejected()
d = Defaults(
smtp={"mailfrom": "whoeve2@example.com", "rcptto": "sieve2est@shelvacu.com"},
username="shelvacu",
)
# test refilter
d.make_tester().smtp_accepted().imap_move_to("MagicRefilter").imap_found_in("com.shelvacu")
d.make_tester().smtp_accepted().imap_move_to("MagicRefilter").imap_found_in(
"com.shelvacu"
)
# refilter doesnt activate on other folders
d.make_tester().smtp_accepted().imap_move_to("testFolder").imap_found_in("testFolder")
d.make_tester().smtp_accepted().imap_move_to("INBOX").imap_found_in("INBOX")
# test the sieve script is working
d.make_tester().smtp_accepted().imap_found_in("com.shelvacu")
# refilter doesnt activate on julie's
d.make_tester(username="julie").smtp_accepted(rcptto="julie@shelvacu.com").imap_move_to("MagicRefilter").imap_found_in("MagicRefilter")
d.make_tester(username="julie").smtp_accepted(rcptto="julie@shelvacu.com").imap_move_to(
"MagicRefilter"
).imap_found_in("MagicRefilter")
d = Defaults(username = "shelvacu")
d.make_tester().smtp_accepted(mailfrom="asshole-spammer@example.com", rcptto="whatever@shelvacu.com", header="List-unsubscribe: whatever").imap_expect(mailbox="com.shelvacu.#spamish", flags=["spamish"])
d.make_tester().smtp_accepted(mailfrom="shipment-tracking@amazon.com", rcptto="amznbsns@shelvacu.com", subject="Your Amazon.com order has shipped (#123-1234)").imap_expect(mailbox="com.shelvacu", flags=["\\Seen","auto-marked-read","amazon-ignore"])
d = Defaults(username="shelvacu")
d.make_tester().smtp_accepted(
mailfrom="asshole-spammer@example.com",
rcptto="whatever@shelvacu.com",
header="List-unsubscribe: whatever",
).imap_expect(mailbox="com.shelvacu.#spamish", flags=["spamish"])
d.make_tester().smtp_accepted(
mailfrom="shipment-tracking@amazon.com",
rcptto="amznbsns@shelvacu.com",
subject="Your Amazon.com order has shipped (#123-1234)",
).imap_expect(
mailbox="com.shelvacu", flags=["\\Seen", "auto-marked-read", "amazon-ignore"]
)
TesterThing().smtp_accepted(rcptto="shelvacu@shelvacu.com", username="shelvacu", smtp_starttls=True)
TesterThing().smtp_accepted(
rcptto="shelvacu@shelvacu.com", username="shelvacu", smtp_starttls=True
)
d = Defaults(smtp = {"submission": True, "rcptto": "foo@example.com"}, username="shelvacu")
d = Defaults(
smtp={"submission": True, "rcptto": "foo@example.com"}, username="shelvacu"
)
d.make_tester().smtp_accepted(mailfrom="me@shelvacu.com").mailpit_received()
d.make_tester().smtp_accepted(mailfrom="me@dis8.net" ).mailpit_not_received()
d.make_tester().smtp_accepted(mailfrom="me@dis8.net").mailpit_not_received()
# julie's emails should NOT get sieve'd like mine
d = Defaults(username="julie")
@@ -302,7 +339,7 @@ d.make_tester().smtp_accepted(rcptto="julie@shelvacu.com").imap_found()
d.make_tester().smtp_accepted(rcptto="sales@theviolincase.com").imap_found()
d.make_tester().smtp_accepted(rcptto="superwow@theviolincase.com").imap_found()
#incoming mail cant be from known domains
# incoming mail cant be from known domains
TesterThing().smtp_rejected(mailfrom="bob@vacu.store")
TesterThing().smtp_rejected(mailfrom="shelvacu@shelvacu.com")
TesterThing().smtp_rejected(mailfrom="julie@shelvacu.com")
@@ -310,19 +347,27 @@ TesterThing().smtp_rejected(mailfrom="@vacu.store")
TesterThing().smtp_rejected(mailfrom="reject-spam-test@example.com")
#people cant send as the wrong person
d = Defaults(smtp = {"submission": True})
# people cant send as the wrong person
d = Defaults(smtp={"submission": True})
d.make_tester().smtp_rejected(mailfrom="julie@shelvacu.com", username="shelvacu")
d.make_tester().smtp_rejected(mailfrom="fubar@theviolincase.com", username="shelvacu")
d.make_tester().smtp_rejected(mailfrom="fubar@vacu.store", username="julie")
d = Defaults(smtp = {"submission": True, "rcptto": "foo@example.com"})
d = Defaults(smtp={"submission": True, "rcptto": "foo@example.com"})
d.make_tester().smtp_accepted(mailfrom="shelvacu@shelvacu.com", username="shelvacu")
d.make_tester().smtp_accepted(mailfrom="shelvacu@shelvacu.com", username="shelvacu@shelvacu.com", password="shelvacu")
d.make_tester().smtp_accepted(
mailfrom="shelvacu@shelvacu.com",
username="shelvacu@shelvacu.com",
password="shelvacu",
)
d.make_tester().smtp_accepted(mailfrom="foo@vacu.store", username="shelvacu")
d.make_tester().smtp_accepted(mailfrom="foo@vacu.store", username="shelvacu@shelvacu.com", password="shelvacu")
d.make_tester().smtp_accepted(
mailfrom="foo@vacu.store", username="shelvacu@shelvacu.com", password="shelvacu"
)
d.make_tester().smtp_accepted(mailfrom="foo@violingifts.com", username="julie")
d.make_tester().smtp_accepted(mailfrom="foo@violingifts.com", username="julie@shelvacu.com", password="julie")
d.make_tester().smtp_accepted(
mailfrom="foo@violingifts.com", username="julie@shelvacu.com", password="julie"
)
# now that there's a bunch of mail and logs and stuff, we can still run a borg backup, right?
liam.succeed("systemctl start auto-borg.service")

View File

@@ -1,6 +1,4 @@
{
...
}:
{ ... }:
{
# systemd.services.dovecot-backup-sftp-server = {
# enable = true;

View File

@@ -22,7 +22,12 @@ in
restartIfChanged = true;
config =
{ lib, config, pkgs, ... }:
{
lib,
config,
pkgs,
...
}:
let
secrets_folder = "/var/lib/vaultwarden/secrets";
services = [ "vaultwarden.service" ];

View File

@@ -9,9 +9,9 @@
let
config = self.checks.x86_64-linux.${name}.config;
vlans = map (m: (
m.virtualisation.vlans ++
(lib.mapAttrsToList (_: v: v.vlan) m.virtualisation.interfaces))) (lib.attrValues config.nodes);
vlans = map (
m: (m.virtualisation.vlans ++ (lib.mapAttrsToList (_: v: v.vlan) m.virtualisation.interfaces))
) (lib.attrValues config.nodes);
nodeHostNames =
let
@@ -19,13 +19,14 @@ let
in
nodesList ++ lib.optional (lib.length nodesList == 1 && !lib.elem "machine" nodesList) "machine";
pythonizeName = name:
pythonizeName =
name:
let
head = lib.substring 0 1 name;
tail = lib.substring 1 (-1) name;
in
(if builtins.match "[A-z_]" head == null then "_" else head) +
lib.stringAsChars (c: if builtins.match "[A-z0-9_]" c == null then "_" else c) tail;
(if builtins.match "[A-z_]" head == null then "_" else head)
+ lib.stringAsChars (c: if builtins.match "[A-z0-9_]" c == null then "_" else c) tail;
uniqueVlans = lib.unique (builtins.concatLists vlans);
vlanNames = map (i: "vlan${toString i}: VLan;") uniqueVlans;