Merge branch 'master' into sqlfluff-bump

This commit is contained in:
Fabian Affolter
2025-01-04 20:45:51 +01:00
committed by GitHub
5766 changed files with 50114 additions and 54178 deletions
+3 -1
View File
@@ -19,6 +19,8 @@ name: Codeowners v2
#
# This split is done because checking code owners requires handling untrusted PR input,
# while requesting code owners requires PR write access, and those shouldn't be mixed.
#
# Note that the latter is also used for ./eval.yml requesting reviewers.
on:
pull_request_target:
@@ -104,6 +106,6 @@ jobs:
run: nix-build ci -A requestReviews
- name: Request reviews
run: result/bin/request-reviews.sh ${{ github.repository }} ${{ github.event.number }} "$OWNERS_FILE"
run: result/bin/request-code-owner-reviews.sh ${{ github.repository }} ${{ github.event.number }} "$OWNERS_FILE"
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
+49 -4
View File
@@ -133,6 +133,7 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ needs.get-merge-commit.outputs.mergedSha }}
fetch-depth: 2
path: nixpkgs
- name: Install Nix
@@ -194,12 +195,18 @@ jobs:
- name: Compare against the base branch
if: steps.baseRunId.outputs.baseRunId
run: |
nix-build nixpkgs/ci -A eval.compare \
git -C nixpkgs worktree add ../base ${{ needs.attrs.outputs.baseSha }}
git -C nixpkgs diff --name-only ${{ needs.attrs.outputs.baseSha }} ${{ needs.attrs.outputs.mergedSha }} \
| jq --raw-input --slurp 'split("\n")[:-1]' > touched-files.json
# Use the base branch to get accurate maintainer info
nix-build base/ci -A eval.compare \
--arg beforeResultDir ./baseResult \
--arg afterResultDir ./prResult \
--arg touchedFilesJson ./touched-files.json \
-o comparison
cat comparison/step-summary.md >> "$GITHUB_STEP_SUMMARY"
# TODO: Request reviews from maintainers for packages whose files are modified in the PR
- name: Upload the combined results
if: steps.baseRunId.outputs.baseRunId
@@ -212,19 +219,42 @@ jobs:
tag:
name: Tag
runs-on: ubuntu-latest
needs: process
needs: [ attrs, process ]
if: needs.process.outputs.baseRunId
permissions:
pull-requests: write
statuses: write
steps:
# See ./codeowners-v2.yml, reuse the same App because we need the same permissions
# Can't use the token received from permissions above, because it can't get enough permissions
- uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0
id: app-token
with:
app-id: ${{ vars.OWNER_APP_ID }}
private-key: ${{ secrets.OWNER_APP_PRIVATE_KEY }}
- name: Download process result
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
with:
name: comparison
path: comparison
- name: Tagging pull request
- name: Install Nix
uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30
# Important: This workflow job runs with extra permissions,
# so we need to make sure to not run untrusted code from PRs
- name: Check out Nixpkgs at the base commit
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ needs.attrs.outputs.baseSha }}
path: base
sparse-checkout: ci
- name: Build the requestReviews derivation
run: nix-build base/ci -A requestReviews
- name: Labelling pull request
run: |
# Get all currently set rebuild labels
gh api \
@@ -252,11 +282,26 @@ jobs:
/repos/"$REPOSITORY"/issues/"$NUMBER"/labels \
-f "labels[]=$toAdd"
done < <(comm -13 before after)
env:
GH_TOKEN: ${{ github.token }}
REPOSITORY: ${{ github.repository }}
NUMBER: ${{ github.event.number }}
- name: Requesting maintainer reviews
run: |
# maintainers.json contains GitHub IDs. Look up handles to request reviews from.
# There appears to be no API to request reviews based on GitHub IDs
jq -r 'keys[]' comparison/maintainers.json \
| while read -r id; do gh api /user/"$id" --jq .login; done \
| GH_TOKEN=${{ steps.app-token.outputs.token }} result/bin/request-reviewers.sh "$REPOSITORY" "$NUMBER" "$AUTHOR"
env:
GH_TOKEN: ${{ github.token }}
REPOSITORY: ${{ github.repository }}
NUMBER: ${{ github.event.number }}
AUTHOR: ${{ github.event.pull_request.user.login }}
- name: Add eval summary to commit statuses
if: ${{ github.event_name == 'pull_request_target' }}
run: |
+4 -5
View File
@@ -1,18 +1,17 @@
name: "No channel PR"
on:
pull_request:
pull_request_target:
# Re-run should be triggered when the base branch is updated, instead of silently failing
types: [opened, synchronize, reopened, edited]
branches:
- 'nixos-**'
- 'nixpkgs-**'
permissions:
contents: read
permissions: {}
jobs:
fail:
permissions:
contents: none
name: "This PR is is targeting a channel branch"
runs-on: ubuntu-latest
steps:
-34
View File
@@ -1,34 +0,0 @@
name: "Set pending OfBorg status"
on:
pull_request_target:
# Sets the ofborg-eval status to "pending" to signal that we are waiting for
# OfBorg even if it is running late. The status will be overwritten by OfBorg
# once it starts evaluation.
# WARNING:
# When extending this action, be aware that $GITHUB_TOKEN allows (restricted) write access to
# the GitHub repository. This means that it should not evaluate user input in a
# way that allows code injection.
permissions:
contents: read
jobs:
action:
name: set-ofborg-pending
if: github.repository_owner == 'NixOS'
permissions:
statuses: write
runs-on: ubuntu-latest
steps:
- name: "Set pending OfBorg status"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
curl \
-X POST \
-H "Accept: application/vnd.github.v3+json" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-d '{"context": "ofborg-eval", "state": "pending", "description": "Waiting for OfBorg..."}' \
"https://api.github.com/repos/NixOS/nixpkgs/commits/${{ github.event.pull_request.head.sha }}/statuses"
-2
View File
@@ -33,8 +33,6 @@ jobs:
max-parallel: 1
matrix:
pairs:
- from: master
into: haskell-updates
- from: release-24.11
into: staging-next-24.11
- from: staging-next-24.11
@@ -0,0 +1,59 @@
# This action periodically merges a merge base of master and staging into haskell-updates.
#
# haskell-updates is based on master (so there are little unrelated failures and the cache
# is already prepopulated), but needs to target staging due to the high amount of rebuilds
# it typically causes. To prevent unrelated commits clattering the GitHub UI, we need to
# take care to only merge the merge-base of master and staging into haskell-updates.
#
# See also https://github.com/NixOS/nixpkgs/issues/361143.
name: "Periodic Merges (haskell-updates)"
on:
schedule:
# * is a special character in YAML so you have to quote this string
# Merge every 24 hours
- cron: '0 0 * * *'
workflow_dispatch:
permissions:
contents: read
jobs:
periodic-merge:
permissions:
contents: write # for devmasx/merge-branch to merge branches
pull-requests: write # for peter-evans/create-or-update-comment to create or update comment
if: github.repository_owner == 'NixOS'
runs-on: ubuntu-latest
name: git merge-base master staging → haskell-updates
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
# Note: If we want to do something similar for more branches, we can move this into a
# separate job, so we can use the matrix strategy again.
- name: Find merge base of master and staging
id: find_merge_base_step
run: |
merge_base="$(git merge-base refs/remotes/origin/master refs/remotes/origin/staging)"
echo "Found merge base: $merge_base" >&2
echo "merge_base=$merge_base" >> "$GITHUB_OUTPUT"
- name: git merge-base master staging → haskell-updates
uses: devmasx/merge-branch@854d3ac71ed1e9deb668e0074781b81fdd6e771f # 1.4.0
with:
type: now
head_to_merge: ${{ steps.find_merge_base_step.outputs.merge_base }}
target_branch: haskell-updates
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Comment on failure
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
if: ${{ failure() }}
with:
issue-number: 367709
body: |
Periodic merge from `${{ steps.find_merge_base_step.outputs.merge_base }}` into `haskell-updates` has [failed](https://github.com/NixOS/nixpkgs/actions/runs/${{ github.run_id }}).
+3
View File
@@ -10,6 +10,9 @@ Fiona Behrens <me@kloenk.dev>
Fiona Behrens <me@kloenk.dev> <me@kloenk.de>
goatastronaut0212 <goatastronaut0212@outlook.com> <goatastronaut0212@proton.me>
Janne Heß <janne@hess.ooo> <dasJ@users.noreply.github.com>
jopejoe1 <nixpkgs@missing.ninja>
jopejoe1 <nixpkgs@missing.ninja> <johannes@joens.email>
jopejoe1 <nixpkgs@missing.ninja> <34899572+jopejoe1@users.noreply.github.com>
Jörg Thalheim <joerg@thalheim.io> <Mic92@users.noreply.github.com>
Lin Jian <me@linj.tech> <linj.dev@outlook.com>
Lin Jian <me@linj.tech> <75130626+jian-lin@users.noreply.github.com>
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2003-2024 Eelco Dolstra and the Nixpkgs/NixOS contributors
Copyright (c) 2003-2025 Eelco Dolstra and the Nixpkgs/NixOS contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
+18 -4
View File
@@ -5,7 +5,11 @@
writeText,
...
}:
{ beforeResultDir, afterResultDir }:
{
beforeResultDir,
afterResultDir,
touchedFilesJson,
}:
let
/*
Derivation that computes which packages are affected (added, changed or removed) between two revisions of nixpkgs.
@@ -77,11 +81,11 @@ let
# - values: lists of `packagePlatformPath`s
diffAttrs = diff beforeAttrs afterAttrs;
rebuilds = uniqueStrings (diffAttrs.added ++ diffAttrs.changed);
rebuildsPackagePlatformAttrs = convertToPackagePlatformAttrs rebuilds;
changed-paths =
let
rebuilds = uniqueStrings (diffAttrs.added ++ diffAttrs.changed);
rebuildsPackagePlatformAttrs = convertToPackagePlatformAttrs rebuilds;
rebuildsByPlatform = groupByPlatform rebuildsPackagePlatformAttrs;
rebuildsByKernel = groupByKernel rebuildsPackagePlatformAttrs;
rebuildCountByKernel = lib.mapAttrs (
@@ -104,10 +108,17 @@ let
);
}
);
maintainers = import ./maintainers.nix {
changedattrs = lib.unique (map (a: a.packagePath) rebuildsPackagePlatformAttrs);
changedpathsjson = touchedFilesJson;
};
in
runCommand "compare"
{
nativeBuildInputs = [ jq ];
maintainers = builtins.toJSON maintainers;
passAsFile = [ "maintainers" ];
}
''
mkdir $out
@@ -115,5 +126,8 @@ runCommand "compare"
cp ${changed-paths} $out/changed-paths.json
jq -r -f ${./generate-step-summary.jq} < ${changed-paths} > $out/step-summary.md
cp "$maintainersPath" "$out/maintainers.json"
# TODO: Compare eval stats
''
+123
View File
@@ -0,0 +1,123 @@
# Almost directly vendored from https://github.com/NixOS/ofborg/blob/5a4e743f192fb151915fcbe8789922fa401ecf48/ofborg/src/maintainers.nix
{ changedattrs, changedpathsjson }:
let
pkgs = import ../../.. {
system = "x86_64-linux";
config = { };
overlays = [ ];
};
inherit (pkgs) lib;
changedpaths = builtins.fromJSON (builtins.readFile changedpathsjson);
anyMatchingFile =
filename:
let
matching = builtins.filter (changed: lib.strings.hasSuffix changed filename) changedpaths;
in
(builtins.length matching) > 0;
anyMatchingFiles = files: (builtins.length (builtins.filter anyMatchingFile files)) > 0;
enrichedAttrs = builtins.map (path: {
path = path;
name = builtins.concatStringsSep "." path;
}) changedattrs;
validPackageAttributes = builtins.filter (
pkg:
if (lib.attrsets.hasAttrByPath pkg.path pkgs) then
(
if (builtins.tryEval (lib.attrsets.attrByPath pkg.path null pkgs)).success then
true
else
builtins.trace "Failed to access ${pkg.name} even though it exists" false
)
else
builtins.trace "Failed to locate ${pkg.name}." false
) enrichedAttrs;
attrsWithPackages = builtins.map (
pkg: pkg // { package = lib.attrsets.attrByPath pkg.path null pkgs; }
) validPackageAttributes;
attrsWithMaintainers = builtins.map (
pkg: pkg // { maintainers = (pkg.package.meta or { }).maintainers or [ ]; }
) attrsWithPackages;
attrsWeCanPing = builtins.filter (
pkg:
if (builtins.length pkg.maintainers) > 0 then
true
else
builtins.trace "Package has no maintainers: ${pkg.name}" false
) attrsWithMaintainers;
relevantFilenames =
drv:
(lib.lists.unique (
builtins.map (pos: lib.strings.removePrefix (toString ../..) pos.file) (
builtins.filter (x: x != null) [
(builtins.unsafeGetAttrPos "maintainers" (drv.meta or { }))
(builtins.unsafeGetAttrPos "src" drv)
# broken because name is always set by stdenv:
# # A hack to make `nix-env -qa` and `nix search` ignore broken packages.
# # TODO(@oxij): remove this assert when something like NixOS/nix#1771 gets merged into nix.
# name = assert validity.handled; name + lib.optionalString
#(builtins.unsafeGetAttrPos "name" drv)
(builtins.unsafeGetAttrPos "pname" drv)
(builtins.unsafeGetAttrPos "version" drv)
# Use ".meta.position" for cases when most of the package is
# defined in a "common" section and the only place where
# reference to the file with a derivation the "pos"
# attribute.
#
# ".meta.position" has the following form:
# "pkgs/tools/package-management/nix/default.nix:155"
# We transform it to the following:
# { file = "pkgs/tools/package-management/nix/default.nix"; }
{ file = lib.head (lib.splitString ":" (drv.meta.position or "")); }
]
)
));
attrsWithFilenames = builtins.map (
pkg: pkg // { filenames = relevantFilenames pkg.package; }
) attrsWithMaintainers;
attrsWithModifiedFiles = builtins.filter (pkg: anyMatchingFiles pkg.filenames) attrsWithFilenames;
listToPing = lib.lists.flatten (
builtins.map (
pkg:
builtins.map (maintainer: {
id = maintainer.githubId;
packageName = pkg.name;
dueToFiles = pkg.filenames;
}) pkg.maintainers
) attrsWithModifiedFiles
);
byMaintainer = lib.lists.foldr (
ping: collector:
collector
// {
"${toString ping.id}" = [
{ inherit (ping) packageName dueToFiles; }
] ++ (collector."${toString ping.id}" or [ ]);
}
) { } listToPing;
textForPackages =
packages: lib.strings.concatStringsSep ", " (builtins.map (pkg: pkg.packageName) packages);
textPerMaintainer = lib.attrsets.mapAttrs (
maintainer: packages: "- @${maintainer} for ${textForPackages packages}"
) byMaintainer;
packagesPerMaintainer = lib.attrsets.mapAttrs (
maintainer: packages: builtins.map (pkg: pkg.packageName) packages
) byMaintainer;
in
packagesPerMaintainer
+22 -18
View File
@@ -11,6 +11,7 @@ rec {
into
{
name = "hello";
packagePath = [ "hello" ];
platform = "aarch64-linux";
}
*/
@@ -30,6 +31,9 @@ rec {
null
else
{
# [ "python312Packages" "numpy" ]
inherit packagePath;
# python312Packages.numpy
inherit name;
@@ -52,12 +56,12 @@ rec {
]
into
[
{ name = "hello"; platform = "aarch64-linux"; }
{ name = "hello"; platform = "x86_64-linux"; }
{ name = "hello"; platform = "aarch64-darwin"; }
{ name = "hello"; platform = "x86_64-darwin"; }
{ name = "bye"; platform = "aarch64-darwin"; }
{ name = "bye"; platform = "x86_64-darwin"; }
{ name = "hello"; platform = "aarch64-linux"; packagePath = [ "hello" ]; }
{ name = "hello"; platform = "x86_64-linux"; packagePath = [ "hello" ]; }
{ name = "hello"; platform = "aarch64-darwin"; packagePath = [ "hello" ]; }
{ name = "hello"; platform = "x86_64-darwin"; packagePath = [ "hello" ]; }
{ name = "bye"; platform = "aarch64-darwin"; packagePath = [ "hello" ]; }
{ name = "bye"; platform = "x86_64-darwin"; packagePath = [ "hello" ]; }
]
*/
convertToPackagePlatformAttrs =
@@ -120,12 +124,12 @@ rec {
Turns
[
{ name = "hello"; platform = "aarch64-linux"; }
{ name = "hello"; platform = "x86_64-linux"; }
{ name = "hello"; platform = "aarch64-darwin"; }
{ name = "hello"; platform = "x86_64-darwin"; }
{ name = "bye"; platform = "aarch64-darwin"; }
{ name = "bye"; platform = "x86_64-darwin"; }
{ name = "hello"; platform = "aarch64-linux"; ... }
{ name = "hello"; platform = "x86_64-linux"; ... }
{ name = "hello"; platform = "aarch64-darwin"; ... }
{ name = "hello"; platform = "x86_64-darwin"; ... }
{ name = "bye"; platform = "aarch64-darwin"; ... }
{ name = "bye"; platform = "x86_64-darwin"; ... }
]
into
{
@@ -145,12 +149,12 @@ rec {
# Turns
# [
# { name = "hello"; platform = "aarch64-linux"; }
# { name = "hello"; platform = "x86_64-linux"; }
# { name = "hello"; platform = "aarch64-darwin"; }
# { name = "hello"; platform = "x86_64-darwin"; }
# { name = "bye"; platform = "aarch64-darwin"; }
# { name = "bye"; platform = "x86_64-darwin"; }
# { name = "hello"; platform = "aarch64-linux"; ... }
# { name = "hello"; platform = "x86_64-linux"; ... }
# { name = "hello"; platform = "aarch64-darwin"; ... }
# { name = "hello"; platform = "x86_64-darwin"; ... }
# { name = "bye"; platform = "aarch64-darwin"; ... }
# { name = "bye"; platform = "x86_64-darwin"; ... }
# ]
#
# into
+3 -2
View File
@@ -14,8 +14,9 @@ stdenvNoCC.mkDerivation {
src = lib.fileset.toSource {
root = ./.;
fileset = lib.fileset.unions [
./get-reviewers.sh
./request-reviews.sh
./get-code-owners.sh
./request-reviewers.sh
./request-code-owner-reviews.sh
./verify-base-branch.sh
./dev-branches.txt
];
@@ -1,8 +1,6 @@
#!/usr/bin/env bash
# Get the code owners of the files changed by a PR,
# suitable to be consumed by the API endpoint to request reviews:
# https://docs.github.com/en/rest/pulls/review-requests?apiVersion=2022-11-28#request-reviewers-for-a-pull-request
# Get the code owners of the files changed by a PR, returning one username per line
set -euo pipefail
@@ -10,18 +8,15 @@ log() {
echo "$@" >&2
}
if (( "$#" < 7 )); then
log "Usage: $0 GIT_REPO OWNERS_FILE BASE_REPO BASE_REF HEAD_REF PR_NUMBER PR_AUTHOR"
if (( "$#" < 4 )); then
log "Usage: $0 GIT_REPO OWNERS_FILE BASE_REF HEAD_REF"
exit 1
fi
gitRepo=$1
ownersFile=$2
baseRepo=$3
baseRef=$4
headRef=$5
prNumber=$6
prAuthor=$7
baseRef=$3
headRef=$4
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' exit
@@ -98,29 +93,4 @@ for file in "${touchedFiles[@]}"; do
done
# Cannot request a review from the author
if [[ -v users[${prAuthor,,}] ]]; then
log "One or more files are owned by the PR author, ignoring"
unset 'users[${prAuthor,,}]'
fi
gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/$baseRepo/pulls/$prNumber/reviews" \
--jq '.[].user.login' > "$tmp/already-reviewed-by"
# And we don't want to rerequest reviews from people who already reviewed
while read -r user; do
if [[ -v users[${user,,}] ]]; then
log "User $user is a code owner but has already left a review, ignoring"
unset 'users[${user,,}]'
fi
done < "$tmp/already-reviewed-by"
# Turn it into a JSON for the GitHub API call to request PR reviewers
jq -n \
--arg users "${!users[*]}" \
'{
reviewers: $users | split(" "),
}'
printf "%s\n" "${!users[@]}"
@@ -77,19 +77,6 @@ if ! "$SCRIPT_DIR"/verify-base-branch.sh "$tmp/nixpkgs.git" "$headRef" "$baseRep
exit 1
fi
log "Getting code owners to request reviews from"
"$SCRIPT_DIR"/get-reviewers.sh "$tmp/nixpkgs.git" "$ownersFile" "$baseRepo" "$baseBranch" "$headRef" "$prNumber" "$prAuthor" > "$tmp/reviewers.json"
log "Requesting reviews from: $(<"$tmp/reviewers.json")"
if ! response=$(effect gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/$baseRepo/pulls/$prNumber/requested_reviewers" \
--input "$tmp/reviewers.json"); then
log "Failed to request reviews: $response"
exit 1
fi
log "Successfully requested reviews"
log "Requesting reviews from code owners"
"$SCRIPT_DIR"/get-code-owners.sh "$tmp/nixpkgs.git" "$ownersFile" "$baseBranch" "$headRef" | \
"$SCRIPT_DIR"/request-reviewers.sh "$baseRepo" "$prNumber" "$prAuthor"
+83
View File
@@ -0,0 +1,83 @@
#!/usr/bin/env bash
# Request reviewers for a PR, reading line-separated usernames on stdin,
# filtering for valid reviewers before using the API endpoint to request reviews:
# https://docs.github.com/en/rest/pulls/review-requests?apiVersion=2022-11-28#request-reviewers-for-a-pull-request
set -euo pipefail
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' exit
log() {
echo "$@" >&2
}
effect() {
if [[ -n "${DRY_MODE:-}" ]]; then
log "Skipping in dry mode:" "${@@Q}"
else
"$@"
fi
}
if (( "$#" < 3 )); then
log "Usage: $0 BASE_REPO PR_NUMBER PR_AUTHOR"
exit 1
fi
baseRepo=$1
prNumber=$2
prAuthor=$3
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' exit
declare -A users=()
while read -r handle && [[ -n "$handle" ]]; do
users[${handle,,}]=
done
# Cannot request a review from the author
if [[ -v users[${prAuthor,,}] ]]; then
log "One or more files are owned by the PR author, ignoring"
unset 'users[${prAuthor,,}]'
fi
gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/$baseRepo/pulls/$prNumber/reviews" \
--jq '.[].user.login' > "$tmp/already-reviewed-by"
# And we don't want to rerequest reviews from people who already reviewed
while read -r user; do
if [[ -v users[${user,,}] ]]; then
log "User $user is a potential reviewer, but has already left a review, ignoring"
unset 'users[${user,,}]'
fi
done < "$tmp/already-reviewed-by"
for user in "${!users[@]}"; do
if ! gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/$baseRepo/collaborators/$user" >&2; then
log "User $user is not a repository collaborator, probably missed the automated invite to the maintainers team (see <https://github.com/NixOS/nixpkgs/issues/234293>), ignoring"
unset 'users[$user]'
fi
done
for user in "${!users[@]}"; do
log "Requesting review from: $user"
if ! response=$(jq -n --arg user "$user" '{ reviewers: [ $user ] }' | \
effect gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/$baseRepo/pulls/$prNumber/requested_reviewers" \
--input -); then
log "Failed to request review from $user: $response"
fi
done
+1 -1
View File
@@ -728,7 +728,7 @@ buildPythonPackage rec {
(fetchDebianPatch {
inherit pname version;
debianRevision = "5";
name = "Add-quotes-to-SOAPAction-header-in-SoapClient.patch";
patch = "Add-quotes-to-SOAPAction-header-in-SoapClient.patch";
hash = "sha256-xA8Wnrpr31H8wy3zHSNfezFNjUJt1HbSXn3qUMzeKc0=";
})
];
-1
View File
@@ -95,6 +95,5 @@ scheme.section.md
swift.section.md
tcl.section.md
texlive.section.md
titanium.section.md
vim.section.md
```
@@ -1,110 +0,0 @@
# Titanium {#titanium}
The Nixpkgs repository contains facilities to deploy a variety of versions of
the [Titanium SDK](https://www.appcelerator.com) versions, a cross-platform
mobile app development framework using JavaScript as an implementation language,
and includes a function abstraction making it possible to build Titanium
applications for Android and iOS devices from source code.
Not all Titanium features supported -- currently, it can only be used to build
Android and iOS apps.
## Building a Titanium app {#building-a-titanium-app}
We can build a Titanium app from source for Android or iOS and for debugging or
release purposes by invoking the `titaniumenv.buildApp {}` function:
```nix
titaniumenv.buildApp {
name = "myapp";
src = ./myappsource;
preBuild = "";
target = "android"; # or 'iphone'
tiVersion = "7.1.0.GA";
release = true;
androidsdkArgs = {
platformVersions = [ "25" "26" ];
};
androidKeyStore = ./keystore;
androidKeyAlias = "myfirstapp";
androidKeyStorePassword = "secret";
xcodeBaseDir = "/Applications/Xcode.app";
xcodewrapperArgs = {
version = "9.3";
};
iosMobileProvisioningProfile = ./myprovisioning.profile;
iosCertificateName = "My Company";
iosCertificate = ./mycertificate.p12;
iosCertificatePassword = "secret";
iosVersion = "11.3";
iosBuildStore = false;
enableWirelessDistribution = true;
installURL = "/installipa.php";
}
```
The `titaniumenv.buildApp {}` function takes the following parameters:
* The `name` parameter refers to the name in the Nix store.
* The `src` parameter refers to the source code location of the app that needs
to be built.
* `preRebuild` contains optional build instructions that are carried out before
the build starts.
* `target` indicates for which device the app must be built. Currently only
'android' and 'iphone' (for iOS) are supported.
* `tiVersion` can be used to optionally override the requested Titanium version
in `tiapp.xml`. If not specified, it will use the version in `tiapp.xml`.
* `release` should be set to true when building an app for submission to the
Google Playstore or Apple Appstore. Otherwise, it should be false.
When the `target` has been set to `android`, we can configure the following
parameters:
* The `androidSdkArgs` parameter refers to an attribute set that propagates all
parameters to the `androidenv.composeAndroidPackages {}` function. This can
be used to install all relevant Android plugins that may be needed to perform
the Android build. If no parameters are given, it will deploy the platform
SDKs for API-levels 25 and 26 by default.
When the `release` parameter has been set to true, you need to provide
parameters to sign the app:
* `androidKeyStore` is the path to the keystore file
* `androidKeyAlias` is the key alias
* `androidKeyStorePassword` refers to the password to open the keystore file.
When the `target` has been set to `iphone`, we can configure the following
parameters:
* The `xcodeBaseDir` parameter refers to the location where Xcode has been
installed. When none value is given, the above value is the default.
* The `xcodewrapperArgs` parameter passes arbitrary parameters to the
`xcodeenv.composeXcodeWrapper {}` function. This can, for example, be used
to adjust the default version of Xcode.
When `release` has been set to true, you also need to provide the following
parameters:
* `iosMobileProvisioningProfile` refers to a mobile provisioning profile needed
for signing.
* `iosCertificateName` refers to the company name in the P12 certificate.
* `iosCertificate` refers to the path to the P12 file.
* `iosCertificatePassword` contains the password to open the P12 file.
* `iosVersion` refers to the iOS SDK version to use. It defaults to the latest
version.
* `iosBuildStore` should be set to `true` when building for the Apple Appstore
submission. For enterprise or ad-hoc builds it should be set to `false`.
When `enableWirelessDistribution` has been enabled, you must also provide the
path of the PHP script (`installURL`) (that is included with the iOS build
environment) to enable wireless ad-hoc installations.
## Emulating or simulating the app {#emulating-or-simulating-the-app}
It is also possible to simulate the correspond iOS simulator build by using
`xcodeenv.simulateApp {}` and emulate an Android APK by using
`androidenv.emulateApp {}`.
+4
View File
@@ -14,3 +14,7 @@ development.md
contributing.md
interoperability.md
```
```{=include=} appendix html:into-file=//release-notes.html
release-notes/release-notes.md
```
+5 -2
View File
@@ -7,9 +7,12 @@ The module system is a language for handling configuration, implemented as a Nix
Compared to plain Nix, it adds documentation, type checking and composition or extensibility.
::: {.note}
This chapter is new and not complete yet. For a gentle introduction to the module system, in the context of NixOS, see [Writing NixOS Modules](https://nixos.org/manual/nixos/unstable/index.html#sec-writing-modules) in the NixOS manual.
:::
This chapter is new and not complete yet.
See also:
- Introduction to the module system, in the context of NixOS, see [Writing NixOS Modules](https://nixos.org/manual/nixos/unstable/index.html#sec-writing-modules) in the NixOS manual.
- Generic guide to the module system on [nix.dev](https://nix.dev/tutorials/module-system/index.html).
:::
## `lib.evalModules` {#module-system-lib-evalModules}
+1 -1
View File
@@ -98,5 +98,5 @@ substituteAllFiles {
}
```
in the resulting derivation, every instance of `@hello@` will be replaced with `there` in `$out/foo.txt` and` `$out/bar.txt`; `baz.txt` will not be processed nor will it appear in `$out`.
in the resulting derivation, every instance of `@hello@` will be replaced with `there` in `$out/foo.txt` and `$out/bar.txt`; `baz.txt` will not be processed nor will it appear in `$out`.
:::
+21 -9
View File
@@ -1,4 +1,7 @@
{
"chap-release-notes": [
"release-notes.html#chap-release-notes"
],
"nixpkgs-manual": [
"index.html#nixpkgs-manual"
],
@@ -50,6 +53,24 @@
"chap-overlays": [
"index.html#chap-overlays"
],
"sec-nixpkgs-release-25.05": [
"release-notes.html#sec-nixpkgs-release-25.05"
],
"sec-nixpkgs-release-25.05-incompatibilities": [
"release-notes.html#sec-nixpkgs-release-25.05-incompatibilities"
],
"sec-nixpkgs-release-25.05-incompatibilities-titanium-removed": [
"release-notes.html#sec-nixpkgs-release-25.05-incompatibilities-titanium-removed",
"index.html#titanium",
"index.html#building-a-titanium-app",
"index.html#emulating-or-simulating-the-app"
],
"sec-nixpkgs-release-25.05-lib": [
"release-notes.html#sec-nixpkgs-release-25.05-lib"
],
"sec-nixpkgs-release-25.05-lib-breaking": [
"release-notes.html#sec-nixpkgs-release-25.05-lib-breaking"
],
"sec-overlays-install": [
"index.html#sec-overlays-install"
],
@@ -3736,15 +3757,6 @@
"sec-language-texlive-lualatex-font-cache": [
"index.html#sec-language-texlive-lualatex-font-cache"
],
"titanium": [
"index.html#titanium"
],
"building-a-titanium-app": [
"index.html#building-a-titanium-app"
],
"emulating-or-simulating-the-app": [
"index.html#emulating-or-simulating-the-app"
],
"vim": [
"index.html#vim"
],
+7
View File
@@ -0,0 +1,7 @@
# Release Notes {#chap-release-notes}
This section lists the release notes for each stable version of Nixpkgs and current unstable revision.
```{=include=} sections
rl-2505.section.md
```
+19
View File
@@ -0,0 +1,19 @@
# Nixpkgs 25.05 (2025.05/??) {#sec-nixpkgs-release-25.05}
## Backward Incompatibilities {#sec-nixpkgs-release-25.05-incompatibilities}
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
### Titanium removed {#sec-nixpkgs-release-25.05-incompatibilities-titanium-removed}
- `titaniumenv`, `titanium`, and `titanium-alloy` have been removed due to lack of maintenance in Nixpkgs.
## Nixpkgs Library {#sec-nixpkgs-release-25.05-lib}
### Breaking changes {#sec-nixpkgs-release-25.05-lib-breaking}
- Structure of the `functor` of some types has changed. `functor` is an implementation detail and should not be relied upon. If you did rely on it let us know in this [PR](https://github.com/NixOS/nixpkgs/pull/363565).
- [`lib.types.enum`](https://nixos.org/manual/nixos/unstable/#sec-option-types-basic): Previously the `functor.payload` was the list of enum values directly. Now it is an attribute set containing the values in the `values` attribute.
- [`lib.types.separatedString`](https://nixos.org/manual/nixos/unstable/#sec-option-types-string): Previously the `functor.payload` was the seperator directly. Now it is an attribute set containing the seperator in the `sep` attribute.
+94 -2
View File
@@ -5892,6 +5892,11 @@
githubId = 283316;
name = "Dane Lipscombe";
};
dlurak = {
github = "dlurak";
githubId = 84224239;
name = "dlurak";
};
dmadisetti = {
email = "nix@madisetti.me";
github = "dmadisetti";
@@ -5988,6 +5993,12 @@
githubId = 57304299;
keys = [ { fingerprint = "33CD 5C0A 673C C54D 661E 5E4C 0DB5 361B EEE5 30AB"; } ];
};
dopplerian = {
name = "Dopplerian";
github = "Dopplerian";
githubId = 53937537;
keys = [ { fingerprint = "BBC4 C071 516B A147 8D07 F9DC D2FD E6EC 2E8C 2BF4"; } ];
};
doriath = {
email = "tomasz.zurkowski@gmail.com";
github = "doriath";
@@ -9218,6 +9229,13 @@
githubId = 287215;
keys = [ { fingerprint = "D618 7A03 A40A 3D56 62F5 4B46 03EF BF83 9A5F DC15"; } ];
};
hlad = {
email = "hlad+nix@hlad.org";
name = "Marek Hladky";
matrix = "@hlad:hlad.org";
github = "hlad";
githubId = 6285728;
};
hleboulanger = {
email = "hleboulanger@protonmail.com";
name = "Harold Leboulanger";
@@ -10134,6 +10152,12 @@
githubId = 45084216;
keys = [ { fingerprint = "1BF9 8D10 E0D0 0B41 5723 5836 4C13 3A84 E646 9228"; } ];
};
jaculabilis = {
name = "Tim Van Baak";
email = "tim.vanbaak@gmail.com";
github = "Jaculabilis";
githubId = 10787844;
};
jaduff = {
email = "jdduffpublic@proton.me";
github = "jaduff";
@@ -11135,11 +11159,11 @@
githubId = 13179;
};
jopejoe1 = {
email = "johannes@joens.email";
email = "nixpkgs@missing.ninja";
matrix = "@jopejoe1:matrix.org";
github = "jopejoe1";
githubId = 34899572;
name = "Johannes Jöns";
name = "jopejoe1";
};
jordanisaacs = {
name = "Jordan Isaacs";
@@ -12511,6 +12535,12 @@
githubId = 168301;
name = "Victor Engmark";
};
l1npengtul = {
email = "l1npengtul@l1npengtul.lol";
github = "l1npengtul";
githubId = 35755164;
name = "l1npengtul";
};
l33tname = {
name = "l33tname";
email = "hi@l33t.name";
@@ -13732,6 +13762,17 @@
githubId = 24735185;
name = "Mahmoud Ayman";
};
mahtaran = {
email = "luka.leer@gmail.com";
github = "mahtaran";
githubId = 22727323;
name = "Luka Leer";
keys = [
{
fingerprint = "C7FF B72E 0527 423A D470 E132 AA82 C4EB CB16 82E0";
}
];
};
majesticmullet = {
email = "hoccthomas@gmail.com.au";
github = "MajesticMullet";
@@ -15300,6 +15341,12 @@
githubId = 44561540;
name = "Synth Morxemplum";
};
MostafaKhaled = {
email = "mostafa.khaled.5422@gmail.com";
github = "mostafa-khaled775";
githubId = 112074172;
name = "Mostafa Khaled";
};
MostAwesomeDude = {
email = "cds@corbinsimpson.com";
github = "MostAwesomeDude";
@@ -15627,6 +15674,12 @@
githubId = 38578268;
name = "Morgan Wolfe";
};
mx2uller = {
email = "mx2uller@pm.me";
github = "mx2uller";
githubId = 93703653;
name = "Marko Müller";
};
mxkrsv = {
email = "mxkrsv@disroot.org";
github = "mxkrsv";
@@ -15655,6 +15708,12 @@
githubId = 9636071;
name = "Myrl Hex";
};
myypo = {
email = "nikirsmcgl@gmail.com";
github = "myypo";
githubId = 110892040;
name = "Mykyta Polchanov";
};
mzacho = {
email = "nixpkgs@martinzacho.net";
github = "mzacho";
@@ -16560,6 +16619,13 @@
githubId = 22592293;
name = "Kartik Gokte";
};
nullcube = {
email = "nullcub3@gmail.com";
name = "NullCube";
github = "nullcub3";
githubId = 51034487;
matrix = "@nullcube:matrix.org";
};
nullishamy = {
email = "spam@amyerskine.me";
name = "nullishamy";
@@ -18638,6 +18704,12 @@
githubId = 40905037;
name = "qwqawawow";
};
qxrein = {
email = "mnv07@proton.me";
github = "qxrein";
githubId = 101001298;
name = "qxrein";
};
qyliss = {
email = "hi@alyssa.is";
github = "alyssais";
@@ -21657,6 +21729,13 @@
githubId = 22163194;
name = "Stel Abrego";
};
stellessia = {
name = "Rachel Podya";
email = "homicide@disroot.org";
github = "stellessia";
githubId = 81514356;
keys = [ { fingerprint = "38E8 7F79 AE86 CA98 F8BC 45F8 1060 00A0 5E5B DB90"; } ];
};
stepbrobd = {
name = "Yifei Sun";
email = "ysun@hey.com";
@@ -21738,6 +21817,13 @@
githubId = 853468;
name = "Steven Roose";
};
stevestreza = {
email = "nixpkgs@stevestreza.com";
github = "stevestreza";
githubId = 28552;
name = "Steve Streza";
keys = [ { fingerprint = "DFED 4E42 34E7 348C 57D4 6568 C4DC 30F8 5ABC 6FA1"; } ];
};
stianlagstad = {
email = "stianlagstad@gmail.com";
github = "stianlagstad";
@@ -22282,6 +22368,12 @@
github = "teatwig";
githubId = 18734648;
};
tebriel = {
email = "tebriel@frodux.in";
name = "tebriel";
github = "tebriel";
githubId = 821688;
};
techknowlogick = {
email = "techknowlogick@gitea.com";
github = "techknowlogick";
+1
View File
@@ -197,6 +197,7 @@ with lib.maintainers;
siraben
vbgl
alizter
stepbrobd
];
scope = "Maintain the Coq theorem prover and related packages.";
shortName = "Coq";
+2
View File
@@ -79,6 +79,8 @@ let
prepareManualFromMD = ''
cp -r --no-preserve=all $inputs/* .
cp -r ${../../../doc/release-notes} ./release-notes-nixpkgs
substituteInPlace ./manual.md \
--replace-fail '@NIXOS_VERSION@' "${version}"
substituteInPlace ./configuration/configuration.md \
@@ -58,11 +58,16 @@ checks:
before the activation script is run. This behavior is different when the
service is socket-activated, as outlined in the following steps.
- The last thing that is taken into account is whether the unit is a service
and socket-activated. If `X-StopIfChanged` is **not** set, the service
is **restart**ed with the others. If it is set, both the service and the
socket are **stop**ped and the socket is **start**ed, leaving socket
activation to start the service when it's needed.
- The last thing that is taken into account is whether the unit is a
service and socket-activated. A correspondence between a
`.service` and its `.socket` unit is detected automatically, but
services can **opt out** of that detection by setting
`X-NotSocketActivated` to `yes` in their `[Service]`
section. Otherwise, if `X-StopIfChanged` is **not** set, the
service is **restart**ed with the others. If it is set, both the
service and the socket are **stop**ped and the socket is
**start**ed, leaving socket activation to start the service when
it's needed.
## Sysinit reactivation {#sec-sysinit-reactivation}
+16 -4
View File
@@ -1886,11 +1886,23 @@
"sec-release-25.05-notable-changes": [
"release-notes.html#sec-release-25.05-notable-changes"
],
"sec-release-25.05-lib": [
"release-notes.html#sec-release-25.05-lib"
"sec-nixpkgs-release-25.05": [
"release-notes.html#sec-nixpkgs-release-25.05"
],
"sec-release-25.05-lib-breaking": [
"release-notes.html#sec-release-25.05-lib-breaking"
"sec-nixpkgs-release-25.05-incompatibilities": [
"release-notes.html#sec-nixpkgs-release-25.05-incompatibilities"
],
"sec-nixpkgs-release-25.05-incompatibilities-titanium-removed": [
"release-notes.html#sec-nixpkgs-release-25.05-incompatibilities-titanium-removed",
"index.html#titanium",
"index.html#building-a-titanium-app",
"index.html#emulating-or-simulating-the-app"
],
"sec-nixpkgs-release-25.05-lib": [
"release-notes.html#sec-nixpkgs-release-25.05-lib"
],
"sec-nixpkgs-release-25.05-lib-breaking": [
"release-notes.html#sec-nixpkgs-release-25.05-lib-breaking"
],
"sec-release-24.11": [
"release-notes.html#sec-release-24.11"
@@ -51,6 +51,8 @@
- [networking.modemmanager](options.html#opt-networking.modemmanager) has been split out of [networking.networkmanager](options.html#opt-networking.networkmanager). NetworkManager still enables ModemManager by default, but options exist now to run NetworkManager without ModemManager.
- [ncps](https://github.com/kalbasit/ncps), a Nix binary cache proxy service implemented in Go using [go-nix](https://github.com/nix-community/go-nix). Available as [services.ncps](options.html#opt-services.ncps.enable).
- [Conduwuit](https://conduwuit.puppyirl.gay/), a federated chat server implementing the Matrix protocol, forked from Conduit. Available as [services.conduwuit](#opt-services.conduwuit.enable).
- [Traccar](https://www.traccar.org/), a modern GPS Tracking Platform. Available as [services.traccar](#opt-services.traccar.enable).
@@ -79,6 +81,8 @@
- [Actual Budget](https://actualbudget.org/), a local-first personal finance app. Available as [services.actual](#opt-services.actual.enable).
- [immich-public-proxy](https://github.com/alangrainger/immich-public-proxy), a proxy for sharing Immich albums without exposing the Immich API. Available as [services.immich-public-proxy](#opt-services.immich-public-proxy.enable).
- [mqtt-exporter](https://github.com/kpetremann/mqtt-exporter/), a Prometheus exporter for exposing messages from MQTT. Available as [services.prometheus.exporters.mqtt](#opt-services.prometheus.exporters.mqtt.enable).
- [nvidia-gpu](https://github.com/utkuozdemir/nvidia_gpu_exporter), a Prometheus exporter that scrapes `nvidia-smi` for GPU metrics. Available as [services.prometheus.exporters.nvidia-gpu](#opt-services.prometheus.exporters.nvidia-gpu.enable).
@@ -113,6 +117,15 @@
- `ps3-disc-dumper` was updated to 4.2.5, which removed the CLI project and now exclusively offers the GUI
- [](#opt-services.nextcloud.config.dbtype) is unset by default, the previous default was `sqlite`.
This was done because `sqlite` is not a reasonable default since it's
[not recommended by upstream](https://docs.nextcloud.com/server/30/admin_manual/installation/system_requirements.html)
and thus doesn't qualify as default.
- Nextcloud's default FPM pool settings have been increased according to upstream recommentations. It's advised
to review the new defaults and description of
[](#opt-services.nextcloud.poolSettings).
- `asusd` has been upgraded to version 6 which supports multiple aura devices. To account for this, the single `auraConfig` configuration option has been replaced with `auraConfigs` which is an attribute set of config options per each device. The config files may also be now specified as either source files or text strings; to account for this you will need to specify that `text` is used for your existing configs, e.g.:
```diff
-services.asusd.asusdConfig = '''file contents'''
@@ -127,6 +140,11 @@
- `zammad` has had its support for MySQL removed, since it was never working correctly and is now deprecated upstream. Check the [migration guide](https://docs.zammad.org/en/latest/appendix/migrate-to-postgresql.html) for how to convert your database to PostgreSQL.
- The `earlyoom` service is now using upstream systemd service, which enables
hardening and filesystem isolation by default. If you need filesystem write
access or want to access home directory via `killHook`, hardening setting can
be changed via, e.g. `systemd.services.earlyoom.serviceConfig.ProtectSystem`.
- `nodePackages.vls` has been deprecated, as the upstream consumer of it, vetur, has been deprecated by upstream. Upstream suggests migrating to Volar for Vue LSP tooling instead.
- `nodePackages.create-react-native-app` has been removed, as it is deprecated. Upstream suggests using a framework for React Native apps instead.
@@ -299,6 +317,10 @@
- `services.avahi.ipv6` now defaults to true.
- For matrix homeserver Synapse we are now following the upstream recommendation to enable jemalloc as the memory allocator by default.
- `services.kmonad` now creates a determinate symlink (in `/dev/input/by-id/`) to each of KMonad virtual devices.
- `bind.cacheNetworks` now only controls access for recursive queries, where it previously controlled access for all queries.
- Caddy can now be built with plugins by using `caddy.withPlugins`, a `passthru` function that accepts an attribute set as a parameter. The `plugins` argument represents a list of Caddy plugins, with each Caddy plugin being a versioned module. The `hash` argument represents the `vendorHash` of the resulting Caddy source code with the plugins added.
@@ -333,10 +355,6 @@
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
## Nixpkgs Library {#sec-release-25.05-lib}
### Breaking changes {#sec-release-25.05-lib-breaking}
- Structure of the `functor` of some types has changed. `functor` is an implementation detail and should not be relied upon. If you did rely on it let us know in this [PR](https://github.com/NixOS/nixpkgs/pull/363565).
- [`lib.types.enum`](https://nixos.org/manual/nixos/unstable/#sec-option-types-basic): Previously the `functor.payload` was the list of enum values directly. Now it is an attribute set containing the values in the `values` attribute.
- [`lib.types.separatedString`](https://nixos.org/manual/nixos/unstable/#sec-option-types-string): Previously the `functor.payload` was the seperator directly. Now it is an attribute set containing the seperator in the `sep` attribute.
```{=include=} sections
../release-notes-nixpkgs/rl-2505.section.md
```
+8
View File
@@ -65,6 +65,14 @@ let
withWarnings = x:
lib.warnIf (evalConfigArgs?extraArgs) "The extraArgs argument to eval-config.nix is deprecated. Please set config._module.args instead."
lib.warnIf (evalConfigArgs?check) "The check argument to eval-config.nix is deprecated. Please set config._module.check instead."
lib.warnIf (specialArgs?pkgs) ''
You have set specialArgs.pkgs, which means that options like nixpkgs.config
and nixpkgs.overlays will be ignored. If you wish to reuse an already created
pkgs, which you know is configured correctly for this NixOS configuration,
please import the `nixosModules.pkgsReadOnly` module from the nixpkgs flake or
`(modulesPath + "/misc/nixpkgs/read-only.nix"), and set `{ nixpkgs.pkgs = <your pkgs>; }`.
This properly disables the ignored options to prevent future surprises.
''
x;
legacyModules =
-3
View File
@@ -619,9 +619,6 @@ let format' = format; in let
# __noChroot for example).
export HOME=$TMPDIR
NIXOS_INSTALL_BOOTLOADER=1 nixos-enter --root $mountPoint -- /nix/var/nix/profiles/system/bin/switch-to-configuration boot
# The above scripts will generate a random machine-id and we don't want to bake a single ID into all our images
rm -f $mountPoint/etc/machine-id
''}
# Set the ownerships of the contents. The modes are set in preVM.
+3
View File
@@ -579,6 +579,9 @@ in rec {
'' else "")
+ optionalString (def ? stopIfChanged && !def.stopIfChanged) ''
X-StopIfChanged=false
''
+ optionalString (def ? notSocketActivated && def.notSocketActivated) ''
X-NotSocketActivated=true
'' + attrsToSection def.serviceConfig);
};
+12
View File
@@ -535,6 +535,18 @@ in rec {
'';
};
notSocketActivated = mkOption {
type = types.bool;
default = false;
description = ''
If set, a changed unit is never assumed to be
socket-activated on configuration switch, even if
it might have associated socket units. Instead, the unit
will be restarted (or stopped/started) as if it had no
associated sockets.
'';
};
startAt = mkOption {
type = with types; either str (listOf str);
default = [];
+2
View File
@@ -1160,6 +1160,7 @@
./services/networking/nats.nix
./services/networking/nbd.nix
./services/networking/ncdns.nix
./services/networking/ncps.nix
./services/networking/ndppd.nix
./services/networking/nebula.nix
./services/networking/netbird.nix
@@ -1485,6 +1486,7 @@
./services/web-apps/icingaweb2/module-monitoring.nix
./services/web-apps/ifm.nix
./services/web-apps/immich.nix
./services/web-apps/immich-public-proxy.nix
./services/web-apps/invidious.nix
./services/web-apps/invoiceplane.nix
./services/web-apps/isso.nix
+34 -28
View File
@@ -1,40 +1,46 @@
# This module defines a small NixOS configuration. It does not
# contain any graphical stuff.
{ config, lib, ... }:
with lib;
{
documentation.enable = mkDefault false;
lib,
...
}:
let
inherit (lib) mkDefault;
in
{
documentation = {
enable = mkDefault false;
doc.enable = mkDefault false;
info.enable = mkDefault false;
man.enable = mkDefault false;
nixos.enable = mkDefault false;
};
documentation.doc.enable = mkDefault false;
environment = {
# Perl is a default package.
defaultPackages = mkDefault [ ];
stub-ld.enable = mkDefault false;
};
documentation.info.enable = mkDefault false;
documentation.man.enable = mkDefault false;
documentation.nixos.enable = mkDefault false;
# Perl is a default package.
environment.defaultPackages = mkDefault [ ];
environment.stub-ld.enable = mkDefault false;
# The lessopen package pulls in Perl.
programs.less.lessopen = mkDefault null;
programs = {
# The lessopen package pulls in Perl.
less.lessopen = mkDefault null;
command-not-found.enable = mkDefault false;
};
# This pulls in nixos-containers which depends on Perl.
boot.enableContainers = mkDefault false;
programs.command-not-found.enable = mkDefault false;
services = {
logrotate.enable = mkDefault false;
udisks2.enable = mkDefault false;
};
services.logrotate.enable = mkDefault false;
services.udisks2.enable = mkDefault false;
xdg.autostart.enable = mkDefault false;
xdg.icons.enable = mkDefault false;
xdg.mime.enable = mkDefault false;
xdg.sounds.enable = mkDefault false;
xdg = {
autostart.enable = mkDefault false;
icons.enable = mkDefault false;
mime.enable = mkDefault false;
sounds.enable = mkDefault false;
};
}
+1 -1
View File
@@ -75,7 +75,7 @@ let
{
freeformType = attrsOf (either scalarType (listOf scalarType));
# Client system-options file directives are explained here:
# https://www.ibm.com/docs/en/storage-protect/8.1.24?topic=commands-processing-options
# https://www.ibm.com/docs/en/storage-protect/8.1.25?topic=commands-processing-options
options.servername = mkOption {
type = servernameType;
default = name;
@@ -45,6 +45,12 @@ in
description = "Port to run Navidrome on.";
type = port;
};
EnableInsightsCollector = mkOption {
default = false;
description = "Enable anonymous usage data collection, see <https://www.navidrome.org/docs/getting-started/insights/> for details.";
type = bool;
};
};
};
default = { };
+2 -2
View File
@@ -44,8 +44,8 @@ let
borgWrapper () {
local result
borg "$@" && result=$? || result=$?
if [[ -z "${toString cfg.failOnWarnings}" ]] && [[ "$result" == 1 ]]; then
echo "ignoring warning return value 1"
if [[ -z "${toString cfg.failOnWarnings}" ]] && [[ "$result" == 1 || ("$result" -ge 100 && "$result" -le 127) ]]; then
echo "ignoring warning return value $result"
return 0
else
return "$result"
+1 -1
View File
@@ -412,7 +412,7 @@ in
]}
PATH=${config.systemd.services."restic-backups-${name}".environment.PATH}:$PATH
exec ${resticCmd} $@
exec ${resticCmd} "$@"
'') (lib.filterAttrs (_: v: v.createWrapper) config.services.restic.backups);
};
}
+1 -1
View File
@@ -89,7 +89,7 @@ in
environment.HOME = "/var/lib/tsm-backup";
serviceConfig = {
# for exit status description see
# https://www.ibm.com/docs/en/storage-protect/8.1.24?topic=clients-client-return-codes
# https://www.ibm.com/docs/en/storage-protect/8.1.25?topic=clients-client-return-codes
SuccessExitStatus = "4 8";
# The `-se` option must come after the command.
# The `-optfile` option suppresses a `dsm.opt`-not-found warning.
@@ -80,9 +80,10 @@ in
let
args = lib.map lib.escapeShellArg (
[
"-l"
"--verbose"
"--user"
cfg.username
"-i"
"--identity-file"
cfg.identityFilePath
cfg.host
cfg.remoteFilesystem
@@ -205,9 +205,14 @@ in
};
extraConfig = mkOption {
description = "Kubernetes kubelet extra configuration file entries.";
description = ''
Kubernetes kubelet extra configuration file entries.
See also [Set Kubelet Parameters Via A Configuration File](https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/)
and [Kubelet Configuration](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/).
'';
default = { };
type = attrsOf attrs;
type = attrsOf ((pkgs.formats.json { }).type);
};
featureGates = mkOption {
+53 -29
View File
@@ -2,6 +2,7 @@
config,
lib,
pkgs,
utils,
...
}:
@@ -15,6 +16,7 @@ let
options = {
name = lib.mkOption {
type = lib.types.str;
default = name;
example = "laptop-internal";
description = "Keyboard name.";
};
@@ -35,16 +37,16 @@ let
Since KMonad runs as an unprivileged user, it may sometimes
need extra permissions in order to read the keyboard device
file. If your keyboard's device file isn't in the input
group you'll need to list its group in this option.
group, you'll need to list its group in this option.
'';
};
defcfg = {
enable = lib.mkEnableOption ''
Automatically generate the defcfg block.
automatic generation of the defcfg block.
When this is option is set to true the config option for
this keyboard should not include a defcfg block.
When this option is set to true, the config option for
this keyboard should not include a defcfg block
'';
compose = {
@@ -55,15 +57,15 @@ let
};
delay = lib.mkOption {
type = lib.types.int;
type = lib.types.ints.unsigned;
default = 5;
description = "The delay (in milliseconds) between compose key sequences.";
};
};
fallthrough = lib.mkEnableOption "Re-emit unhandled key events.";
fallthrough = lib.mkEnableOption "re-emitting unhandled key events";
allowCommands = lib.mkEnableOption "Allow keys to run shell commands.";
allowCommands = lib.mkEnableOption "keys to run shell commands";
};
config = lib.mkOption {
@@ -71,12 +73,10 @@ let
description = "Keyboard configuration.";
};
};
config = {
name = lib.mkDefault name;
};
};
mkName = name: "kmonad-" + name;
# Create a complete KMonad configuration file:
mkCfg =
keyboard:
@@ -84,7 +84,7 @@ let
defcfg = ''
(defcfg
input (device-file "${keyboard.device}")
output (uinput-sink "kmonad-${keyboard.name}")
output (uinput-sink "${mkName keyboard.name}")
${lib.optionalString (keyboard.defcfg.compose.key != null) ''
cmp-seq ${keyboard.defcfg.compose.key}
cmp-seq-delay ${toString keyboard.defcfg.compose.delay}
@@ -95,9 +95,9 @@ let
'';
in
pkgs.writeTextFile {
name = "kmonad-${keyboard.name}.cfg";
name = "${mkName keyboard.name}.kbd";
text = lib.optionalString keyboard.defcfg.enable (defcfg + "\n") + keyboard.config;
checkPhase = "${cfg.package}/bin/kmonad -d $out";
checkPhase = "${lib.getExe cfg.package} -d $out";
};
# Build a systemd path config that starts the service below when a
@@ -105,7 +105,7 @@ let
mkPath =
keyboard:
let
name = "kmonad-${keyboard.name}";
name = mkName keyboard.name;
in
lib.nameValuePair name {
description = "KMonad trigger for ${keyboard.device}";
@@ -119,19 +119,8 @@ let
# Build a systemd service that starts KMonad:
mkService =
keyboard:
let
cmd =
[
(lib.getExe cfg.package)
"--input"
''device-file "${keyboard.device}"''
]
++ cfg.extraArgs
++ [ "${mkCfg keyboard}" ];
in
lib.nameValuePair "kmonad-${keyboard.name}" {
lib.nameValuePair (mkName keyboard.name) {
description = "KMonad for ${keyboard.device}";
script = lib.escapeShellArgs cmd;
unitConfig = {
# Control rate limiting.
# Stop the restart logic if we restart more than
@@ -140,6 +129,10 @@ let
StartLimitBurst = 5;
};
serviceConfig = {
ExecStart = ''
${lib.getExe cfg.package} ${mkCfg keyboard} \
${utils.escapeSystemdExecArgs cfg.extraArgs}
'';
Restart = "always";
# Restart at increasing intervals from 2s to 1m
RestartSec = 2;
@@ -155,13 +148,26 @@ let
config.users.groups.uinput.name
] ++ keyboard.extraGroups;
};
# make sure the new config is used after nixos-rebuild switch
# stopIfChanged controls[0] how a service is "restarted" during
# nixos-rebuild switch. By default, stopIfChanged is true, which stops
# the old service and then starts the new service after config updates.
# Since we use path-based activation[1] here, the service unit will
# immediately[2] be started by the path unit. Probably that start is
# before config updates, whcih causes the service unit to use the old
# config after nixos-rebuild switch. Setting stopIfChanged to false works
# around this issue by restarting the service after config updates.
# [0]: https://nixos.org/manual/nixos/unstable/#sec-switching-systems
# [1]: man 7 daemon
# [2]: man 5 systemd.path
stopIfChanged = false;
};
in
{
options.services.kmonad = {
enable = lib.mkEnableOption "KMonad: An advanced keyboard manager.";
enable = lib.mkEnableOption "KMonad: an advanced keyboard manager";
package = lib.mkPackageOption pkgs "kmonad" { };
package = lib.mkPackageOption pkgs "KMonad" { default = "kmonad"; };
keyboards = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule keyboard);
@@ -183,9 +189,27 @@ in
config = lib.mkIf cfg.enable {
hardware.uinput.enable = true;
services.udev.extraRules =
let
mkRule = name: ''
ACTION=="add", KERNEL=="event*", SUBSYSTEM=="input", ATTRS{name}=="${name}", ATTRS{id/product}=="5679", ATTRS{id/vendor}=="1235", SYMLINK+="input/by-id/${name}"
'';
in
lib.foldlAttrs (
rules: _: keyboard:
rules + "\n" + mkRule (mkName keyboard.name)
) "" cfg.keyboards;
systemd = {
paths = lib.mapAttrs' (_: mkPath) cfg.keyboards;
services = lib.mapAttrs' (_: mkService) cfg.keyboards;
};
};
meta = {
maintainers = with lib.maintainers; [
linj
rvdp
];
};
}
+4 -4
View File
@@ -459,10 +459,10 @@ in
fi
'';
systemd.services.systemd-udevd =
{ restartTriggers = [ config.environment.etc."udev/rules.d".source ];
};
systemd.services.systemd-udevd = {
restartTriggers = [ config.environment.etc."udev/rules.d".source ];
notSocketActivated = true;
};
};
imports = [
+2 -1
View File
@@ -705,7 +705,7 @@ in
withJemalloc = mkOption {
type = types.bool;
default = false;
default = true;
description = ''
Whether to preload jemalloc to reduce memory fragmentation and overall usage.
'';
@@ -1462,6 +1462,7 @@ in
baseServiceConfig = {
environment = optionalAttrs (cfg.withJemalloc) {
LD_PRELOAD = "${pkgs.jemalloc}/lib/libjemalloc.so";
PYTHONMALLOC = "malloc";
};
serviceConfig = {
Type = "notify";
+10 -3
View File
@@ -20,6 +20,12 @@ in
default = 5055;
description = ''The port which the Jellyseerr web UI should listen to.'';
};
configDir = lib.mkOption {
type = lib.types.path;
default = "/var/lib/jellyseerr/config";
description = "Config data directory";
};
};
config = lib.mkIf cfg.enable {
@@ -27,14 +33,15 @@ in
description = "Jellyseerr, a requests manager for Jellyfin";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
environment.PORT = toString cfg.port;
environment = {
PORT = toString cfg.port;
CONFIG_DIRECTORY = cfg.configDir;
};
serviceConfig = {
Type = "exec";
StateDirectory = "jellyseerr";
WorkingDirectory = "${cfg.package}/libexec/jellyseerr/deps/jellyseerr";
DynamicUser = true;
ExecStart = lib.getExe cfg.package;
BindPaths = [ "/var/lib/jellyseerr/:${cfg.package}/libexec/jellyseerr/deps/jellyseerr/config/" ];
Restart = "on-failure";
ProtectHome = true;
ProtectSystem = "strict";
+6 -3
View File
@@ -24,9 +24,12 @@ in
description = "Whether to enable the PyKMS service.";
};
package = lib.mkPackageOption pkgs "pykms" { };
listenAddress = lib.mkOption {
type = lib.types.str;
default = "0.0.0.0";
example = "::";
description = "The IP address on which to listen.";
};
@@ -78,13 +81,13 @@ in
wantedBy = [ "multi-user.target" ];
# python programs with DynamicUser = true require HOME to be set
environment.HOME = libDir;
serviceConfig = with pkgs; {
serviceConfig = {
DynamicUser = true;
StateDirectory = baseNameOf libDir;
ExecStartPre = "${lib.getBin pykms}/libexec/create_pykms_db.sh ${libDir}/clients.db";
ExecStartPre = "${lib.getBin cfg.package}/libexec/create_pykms_db.sh ${libDir}/clients.db";
ExecStart = lib.concatStringsSep " " (
[
"${lib.getBin pykms}/bin/server"
"${lib.getBin cfg.package}/bin/server"
"--logfile=STDOUT"
"--loglevel=${cfg.logLevel}"
"--sqlite=${libDir}/clients.db"
@@ -31,18 +31,17 @@ in
'';
};
tokenPath = mkOption {
environmentFile = mkOption {
type = path;
description = ''
A run-time path to the token file, which is supposed to be provisioned
outside of Nix store.
An environment file containg at least the FASTLY_API_TOKEN= environment
variable.
'';
};
};
serviceOpts = {
serviceConfig = {
LoadCredential = "fastly-api-token:${cfg.tokenPath}";
Environment = [ "FASTLY_API_TOKEN=%d/fastly-api-token" ];
EnvironmentFile = cfg.environmentFile;
ExecStart = escapeSystemdExecArgs (
[
(getExe pkgs.prometheus-fastly-exporter)
@@ -36,8 +36,6 @@ let
${lib.optionalString (cfg.cert != null) "cert=${cfg.cert}"}
${lib.optionalString (cfg.pkey != null) "pkey=${cfg.pkey}"}
${lib.optionalString (cfg.dh-file != null) "dh-file=${cfg.dh-file}"}
no-stdout-log
syslog
pidfile=${pidfile}
${lib.optionalString cfg.secure-stun "secure-stun"}
${lib.optionalString cfg.no-cli "no-cli"}
+326
View File
@@ -0,0 +1,326 @@
{
config,
pkgs,
lib,
...
}:
let
cfg = config.services.ncps;
logLevels = [
"trace"
"debug"
"info"
"warn"
"error"
"fatal"
"panic"
];
globalFlags = lib.concatStringsSep " " (
[ "--log-level='${cfg.logLevel}'" ]
++ (lib.optionals cfg.openTelemetry.enable (
[
"--otel-enabled"
]
++ (lib.optional (
cfg.openTelemetry.grpcURL != null
) "--otel-grpc-url='${cfg.openTelemetry.grpcURL}'")
))
);
serveFlags = lib.concatStringsSep " " (
[
"--cache-hostname='${cfg.cache.hostName}'"
"--cache-data-path='${cfg.cache.dataPath}'"
"--cache-database-url='${cfg.cache.databaseURL}'"
"--server-addr='${cfg.server.addr}'"
]
++ (lib.optional cfg.cache.allowDeleteVerb "--cache-allow-delete-verb")
++ (lib.optional cfg.cache.allowPutVerb "--cache-allow-put-verb")
++ (lib.optional (cfg.cache.maxSize != null) "--cache-max-size='${cfg.cache.maxSize}'")
++ (lib.optionals (cfg.cache.lru.schedule != null) [
"--cache-lru-schedule='${cfg.cache.lru.schedule}'"
"--cache-lru-schedule-timezone='${cfg.cache.lru.scheduleTimeZone}'"
])
++ (lib.optional (cfg.cache.secretKeyPath != null) "--cache-secret-key-path='%d/secretKey'")
++ (lib.forEach cfg.upstream.caches (url: "--upstream-cache='${url}'"))
++ (lib.forEach cfg.upstream.publicKeys (pk: "--upstream-public-key='${pk}'"))
);
isSqlite = lib.strings.hasPrefix "sqlite:" cfg.cache.databaseURL;
dbPath = lib.removePrefix "sqlite:" cfg.cache.databaseURL;
dbDir = dirOf dbPath;
in
{
options = {
services.ncps = {
enable = lib.mkEnableOption "ncps: Nix binary cache proxy service implemented in Go";
package = lib.mkPackageOption pkgs "ncps" { };
dbmatePackage = lib.mkPackageOption pkgs "dbmate" { };
openTelemetry = {
enable = lib.mkEnableOption "Enable OpenTelemetry logs, metrics, and tracing";
grpcURL = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
Configure OpenTelemetry gRPC URL. Missing or "https" scheme enables
secure gRPC, "insecure" otherwise. Omit to emit telemetry to
stdout.
'';
};
};
logLevel = lib.mkOption {
type = lib.types.enum logLevels;
default = "info";
description = ''
Set the level for logging. Refer to
<https://pkg.go.dev/github.com/rs/zerolog#readme-leveled-logging> for
more information.
'';
};
cache = {
allowDeleteVerb = lib.mkEnableOption ''
Whether to allow the DELETE verb to delete narinfo and nar files from
the cache.
'';
allowPutVerb = lib.mkEnableOption ''
Whether to allow the PUT verb to push narinfo and nar files directly
to the cache.
'';
hostName = lib.mkOption {
type = lib.types.str;
description = ''
The hostname of the cache server. **This is used to generate the
private key used for signing store paths (.narinfo)**
'';
};
dataPath = lib.mkOption {
type = lib.types.str;
default = "/var/lib/ncps";
description = ''
The local directory for storing configuration and cached store paths
'';
};
databaseURL = lib.mkOption {
type = lib.types.str;
default = "sqlite:${cfg.cache.dataPath}/db/db.sqlite";
defaultText = "sqlite:/var/lib/ncps/db/db.sqlite";
description = ''
The URL of the database (currently only SQLite is supported)
'';
};
lru = {
schedule = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "0 2 * * *";
description = ''
The cron spec for cleaning the store to keep it under
config.ncps.cache.maxSize. Refer to
https://pkg.go.dev/github.com/robfig/cron/v3#hdr-Usage for
documentation.
'';
};
scheduleTimeZone = lib.mkOption {
type = lib.types.str;
default = "Local";
example = "America/Los_Angeles";
description = ''
The name of the timezone to use for the cron schedule. See
<https://en.wikipedia.org/wiki/List_of_tz_database_time_zones>
for a comprehensive list of possible values for this setting.
'';
};
};
maxSize = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "100G";
description = ''
The maximum size of the store. It can be given with units such as
5K, 10G etc. Supported units: B, K, M, G, T.
'';
};
secretKeyPath = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
The path to load the secretKey for signing narinfos. Leave this
empty to automatically generate a private/public key.
'';
};
};
server = {
addr = lib.mkOption {
type = lib.types.str;
default = ":8501";
description = ''
The address and port the server listens on.
'';
};
};
upstream = {
caches = lib.mkOption {
type = lib.types.listOf lib.types.str;
example = [ "https://cache.nixos.org" ];
description = ''
A list of URLs of upstream binary caches.
'';
};
publicKeys = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
example = [ "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" ];
description = ''
A list of public keys of upstream caches in the format
`host[-[0-9]*]:public-key`. This flag is used to verify the
signatures of store paths downloaded from upstream caches.
'';
};
};
};
};
config = lib.mkIf cfg.enable {
assertions = [
{
assertion = cfg.cache.lru.schedule == null || cfg.cache.maxSize != null;
message = "You must specify config.ncps.cache.lru.schedule when config.ncps.cache.maxSize is set";
}
{
assertion = cfg.cache.secretKeyPath == null || (builtins.pathExists cfg.cache.secretKeyPath);
message = "config.ncps.cache.secresecretKeyPath=${cfg.cache.secretKeyPath} must exist but does not";
}
];
users.users.ncps = {
isSystemUser = true;
group = "ncps";
};
users.groups.ncps = { };
systemd.services.ncps-create-datadirs = {
description = "Created required directories by ncps";
serviceConfig = {
Type = "oneshot";
UMask = "0066";
};
script =
(lib.optionalString (cfg.cache.dataPath != "/var/lib/ncps") ''
if ! test -d ${cfg.cache.dataPath}; then
mkdir -p ${cfg.cache.dataPath}
chown ncps:ncps ${cfg.cache.dataPath}
fi
'')
+ (lib.optionalString isSqlite ''
if ! test -d ${dbDir}; then
mkdir -p ${dbDir}
chown ncps:ncps ${dbDir}
fi
'');
wantedBy = [ "ncps.service" ];
before = [ "ncps.service" ];
};
systemd.services.ncps = {
description = "ncps binary cache proxy service";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
preStart = ''
${lib.getExe cfg.dbmatePackage} --migrations-dir=${cfg.package}/share/ncps/db/migrations --url=${cfg.cache.databaseURL} up
'';
serviceConfig = lib.mkMerge [
{
ExecStart = "${lib.getExe cfg.package} ${globalFlags} serve ${serveFlags}";
User = "ncps";
Group = "ncps";
Restart = "on-failure";
RuntimeDirectory = "ncps";
}
# credentials
(lib.mkIf (cfg.cache.secretKeyPath != null) {
LoadCredential = "secretKey:${cfg.cache.secretKeyPath}";
})
# ensure permissions on required directories
(lib.mkIf (cfg.cache.dataPath != "/var/lib/ncps") {
ReadWritePaths = [ cfg.cache.dataPath ];
})
(lib.mkIf (cfg.cache.dataPath == "/var/lib/ncps") {
StateDirectory = "ncps";
StateDirectoryMode = "0700";
})
(lib.mkIf (isSqlite && !lib.strings.hasPrefix "/var/lib/ncps" dbDir) {
ReadWritePaths = [ dbDir ];
})
# Hardening
{
SystemCallFilter = [
"@system-service"
"~@privileged"
"~@resources"
];
CapabilityBoundingSet = "";
PrivateUsers = true;
DevicePolicy = "closed";
DeviceAllow = [ "" ];
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectControlGroups = true;
ProtectKernelLogs = true;
ProtectHostname = true;
ProtectClock = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
ProtectHome = true;
RestrictSUIDSGID = true;
RestrictRealtime = true;
MemoryDenyWriteExecute = true;
ProcSubset = "pid";
RestrictNamespaces = true;
SystemCallArchitectures = "native";
PrivateNetwork = false;
PrivateTmp = true;
PrivateDevices = true;
PrivateMounts = true;
NoNewPrivileges = true;
LockPersonality = true;
RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
LimitNOFILE = 65536;
UMask = "0066";
}
];
unitConfig.RequiresMountsFor = lib.concatStringsSep " " (
[ "${cfg.cache.dataPath}" ] ++ lib.optional (isSqlite) dbDir
);
};
};
meta.maintainers = with lib.maintainers; [ kalbasit ];
}
+2 -2
View File
@@ -143,10 +143,10 @@ in
restartTriggers = [ cfg.unifiPackage cfg.mongodbPackage ];
serviceConfig = {
Type = "simple";
Type = "notify";
ExecStart = "${cmd} start";
ExecStop = "${cmd} stop";
Restart = "on-failure";
Restart = "always";
TimeoutSec = "5min";
User = "unifi";
UMask = "0077";
+1 -1
View File
@@ -419,7 +419,7 @@ in
${optionalString (containsGutenprint cfg.drivers) ''
if [ -d /var/lib/cups/ppd ]; then
${getGutenprint cfg.drivers}/bin/cups-genppdupdate -p /var/lib/cups/ppd
${getGutenprint cfg.drivers}/bin/cups-genppdupdate -x -p /var/lib/cups/ppd
fi
''}
'';
+1 -1
View File
@@ -130,7 +130,7 @@ in
type = addCheck str (
x:
cfg.svcManager == "command"
|| elem x [
|| lib.elem x [
"restart"
"reload"
"nop"
+1 -1
View File
@@ -193,7 +193,7 @@ in
ExecStart =
with cfg;
let
opt = n: v: optionalString (v != null) ''-${n}="${v}"'';
opt = n: v: lib.optionalString (v != null) ''-${n}="${v}"'';
in
lib.concatStringsSep " \\\n" [
"${pkgs.cfssl}/bin/cfssl serve"
@@ -94,14 +94,14 @@ in
Restart = "always";
ExecStart =
with cfg;
concatStringsSep " " (
lib.concatStringsSep " " (
[
(lib.getExe cfg.package)
"-logtostderr"
"-host=${listenAddress}"
"-port=${toString port}"
]
++ optionals prometheus.enable [
++ lib.optionals prometheus.enable [
"-enable_prometheus"
"-prometheus_host=${prometheus.listenAddress}"
"-prometheus_port=${toString prometheus.port}"
@@ -149,7 +149,7 @@ in
};
};
networking.firewall.allowedTCPPorts = with cfg; optionals openFirewall [ port ];
networking.firewall.allowedTCPPorts = with cfg; lib.optionals openFirewall [ port ];
};
meta.maintainers = with lib.maintainers; [ azahi ];
+2 -2
View File
@@ -60,7 +60,7 @@ in
Restart = "always";
ExecStart =
with cfg;
concatStringsSep " " (
lib.concatStringsSep " " (
[
"${pkgs.endlessh}/bin/endlessh"
"-p ${toString port}"
@@ -109,7 +109,7 @@ in
};
};
networking.firewall.allowedTCPPorts = with cfg; optionals openFirewall [ port ];
networking.firewall.allowedTCPPorts = with cfg; lib.optionals openFirewall [ port ];
};
meta.maintainers = with lib.maintainers; [ azahi ];
+11 -5
View File
@@ -150,7 +150,7 @@ in
};
Ebpf.ModulesPath = lib.mkOption {
type = lib.types.path;
type = lib.types.nullOr lib.types.path;
default =
if cfg.settings.ProcMonitorMethod == "ebpf" then
"${config.boot.kernelPackages.opensnitch-ebpf}/etc/opensnitchd"
@@ -202,10 +202,16 @@ in
services.opensnitchd = {
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = [
""
"${pkgs.opensnitch}/bin/opensnitchd --config-file ${format.generate "default-config.json" cfg.settings}"
];
ExecStart =
let
preparedSettings = removeAttrs cfg.settings (
lib.optional (cfg.settings.ProcMonitorMethod != "ebpf") "Ebpf"
);
in
[
""
"${pkgs.opensnitch}/bin/opensnitchd --config-file ${format.generate "default-config.json" preparedSettings}"
];
};
preStart = lib.mkIf (cfg.rules != { }) (
let
+111 -102
View File
@@ -5,7 +5,6 @@
pkgs,
...
}:
with builtins;
let
cfg = config.services.tor;
opt = options.services.tor;
@@ -15,7 +14,7 @@ let
See [torrc manual](https://2019.www.torproject.org/docs/tor-manual.html.en#${option}).
'';
bindsPrivilegedPort =
any
lib.any
(
p0:
let
@@ -25,20 +24,22 @@ let
false
else
let
p2 = if isInt p1 then p1 else toInt p1;
p2 = if lib.isInt p1 then p1 else lib.toInt p1;
in
p1 != null && 0 < p2 && p2 < 1024
)
(flatten [
cfg.settings.ORPort
cfg.settings.DirPort
cfg.settings.DNSPort
cfg.settings.ExtORPort
cfg.settings.HTTPTunnelPort
cfg.settings.NATDPort
cfg.settings.SOCKSPort
cfg.settings.TransPort
]);
(
lib.flatten [
cfg.settings.ORPort
cfg.settings.DirPort
cfg.settings.DNSPort
cfg.settings.ExtORPort
cfg.settings.HTTPTunnelPort
cfg.settings.NATDPort
cfg.settings.SOCKSPort
cfg.settings.TransPort
]
);
optionBool =
optionName:
lib.mkOption {
@@ -68,7 +69,7 @@ let
description = (descriptionGeneric optionName);
};
optionAddress = lib.mkOption {
type = with types; nullOr str;
type = with lib.types; nullOr str;
default = null;
example = "0.0.0.0";
description = ''
@@ -76,7 +77,7 @@ let
'';
};
optionUnix = lib.mkOption {
type = with types; nullOr path;
type = with lib.types; nullOr path;
default = null;
description = ''
Unix domain socket path to use.
@@ -84,7 +85,7 @@ let
};
optionPort = lib.mkOption {
type =
with types;
with lib.types;
nullOr (oneOf [
port
(enum [ "auto" ])
@@ -125,8 +126,8 @@ let
);
config = {
flags =
filter (name: config.${name} == true) isolateFlags
++ optional (config.SessionGroup != null) "SessionGroup=${toString config.SessionGroup}";
lib.filter (name: config.${name} == true) isolateFlags
++ lib.optional (config.SessionGroup != null) "SessionGroup=${toString config.SessionGroup}";
};
}
))
@@ -195,14 +196,14 @@ let
config = lib.mkIf doConfig {
# Only add flags in SOCKSPort to avoid duplicates
flags =
filter (name: config.${name} == true) flags
++ optional (config.SessionGroup != null) "SessionGroup=${toString config.SessionGroup}";
lib.filter (name: config.${name} == true) flags
++ lib.optional (config.SessionGroup != null) "SessionGroup=${toString config.SessionGroup}";
};
}
))
];
optionFlags = lib.mkOption {
type = with types; listOf str;
type = with lib.types; listOf str;
default = [ ];
};
optionORPort =
@@ -243,7 +244,7 @@ let
}
);
config = {
flags = filter (name: config.${name} == true) flags;
flags = lib.filter (name: config.${name} == true) flags;
};
}
))
@@ -270,33 +271,33 @@ let
k: v:
if v == null then
""
else if isBool v then
else if lib.isBool v then
(if v then "1" else "0")
else if v ? "unix" && v.unix != null then
"unix:" + v.unix + optionalString (v ? "flags") (" " + concatStringsSep " " v.flags)
"unix:" + v.unix + lib.optionalString (v ? "flags") (" " + lib.concatStringsSep " " v.flags)
else if v ? "port" && v.port != null then
optionalString (v ? "addr" && v.addr != null) "${v.addr}:"
lib.optionalString (v ? "addr" && v.addr != null) "${v.addr}:"
+ toString v.port
+ optionalString (v ? "flags") (" " + concatStringsSep " " v.flags)
+ lib.optionalString (v ? "flags") (" " + lib.concatStringsSep " " v.flags)
else if k == "ServerTransportPlugin" then
optionalString (v.transports != [ ]) "${concatStringsSep "," v.transports} exec ${v.exec}"
lib.optionalString (v.transports != [ ]) "${lib.concatStringsSep "," v.transports} exec ${v.exec}"
else if k == "HidServAuth" then
v.onion + " " + v.auth
else
generators.mkValueStringDefault { } v;
lib.generators.mkValueStringDefault { } v;
genTorrc =
settings:
generators.toKeyValue
lib.generators.toKeyValue
{
listsAsDuplicateKeys = true;
mkKeyValue = k: generators.mkKeyValueDefault { mkValueString = mkValueString k; } " " k;
mkKeyValue = k: lib.generators.mkKeyValueDefault { mkValueString = mkValueString k; } " " k;
}
(
lib.mapAttrs (
k: v:
# Not necesssary, but prettier rendering
if
elem k [
lib.elem k [
"AutomapHostsSuffixes"
"DirPolicy"
"ExitPolicy"
@@ -304,15 +305,15 @@ let
]
&& v != [ ]
then
concatStringsSep "," v
lib.concatStringsSep "," v
else
v
) (lib.filterAttrs (k: v: !(v == null || v == "")) settings)
);
torrc = pkgs.writeText "torrc" (
genTorrc cfg.settings
+ concatStrings (
mapAttrsToList (
+ lib.concatStrings (
lib.mapAttrsToList (
name: onion: "HiddenServiceDir ${onion.path}\n" + genTorrc onion.settings
) cfg.relay.onionServices
)
@@ -506,7 +507,7 @@ in
};
type = lib.types.attrsOf (
lib.types.submodule (
{ name, config, ... }:
{ ... }:
{
options.clientAuthorizations = lib.mkOption {
description = ''
@@ -748,7 +749,7 @@ in
]);
apply = map (
v:
if isInt v then
if lib.isInt v then
{
port = v;
target = null;
@@ -810,11 +811,11 @@ in
};
};
config = {
path = mkDefault ((if config.secretKey == null then stateDir else runDir) + "/onion/${name}");
path = lib.mkDefault ((if config.secretKey == null then stateDir else runDir) + "/onion/${name}");
settings.HiddenServiceVersion = config.version;
settings.HiddenServiceAuthorizeClient =
if config.authorizeClient != null then
config.authorizeClient.authType + " " + concatStringsSep "," config.authorizeClient.clientNames
config.authorizeClient.authType + " " + lib.concatStringsSep "," config.authorizeClient.clientNames
else
null;
settings.HiddenServicePort = map (
@@ -890,7 +891,7 @@ in
options.ConnDirectionStatistics = optionBool "ConnDirectionStatistics";
options.ConstrainedSockets = optionBool "ConstrainedSockets";
options.ContactInfo = optionString "ContactInfo";
options.ControlPort = lib.mkOption rec {
options.ControlPort = lib.mkOption {
description = (descriptionGeneric "ControlPort");
default = [ ];
example = [ { port = 9051; } ];
@@ -927,7 +928,7 @@ in
}
);
config = {
flags = filter (name: config.${name} == true) flags;
flags = lib.filter (name: config.${name} == true) flags;
};
}
))
@@ -996,7 +997,7 @@ in
}
))
]);
apply = p: if isInt p || isString p then { port = p; } else p;
apply = p: if lib.isInt p || lib.isString p then { port = p; } else p;
};
options.ExtORPortCookieAuthFile = optionPath "ExtORPortCookieAuthFile";
options.ExtORPortCookieAuthFileGroupReadable = optionBool "ExtORPortCookieAuthFileGroupReadable";
@@ -1177,8 +1178,11 @@ in
# Not sure if `cfg.relay.role == "private-bridge"` helps as tor
# sends a lot of stats
warnings =
optional
(cfg.settings.BridgeRelay && flatten (mapAttrsToList (n: o: o.map) cfg.relay.onionServices) != [ ])
lib.optional
(
cfg.settings.BridgeRelay
&& lib.flatten (lib.mapAttrsToList (n: o: o.map) cfg.relay.onionServices) != [ ]
)
''
Running Tor hidden services on a public relay makes the
presence of hidden services visible through simple statistical
@@ -1189,21 +1193,21 @@ in
actually hide your hidden services. In either case, you can
always create a container/VM with a separate Tor daemon instance.
''
++ flatten (
mapAttrsToList (
++ lib.flatten (
lib.mapAttrsToList (
n: o:
optionals (o.settings.HiddenServiceVersion == 2) [
(optional (o.settings.HiddenServiceExportCircuitID != null) ''
lib.optionals (o.settings.HiddenServiceVersion == 2) [
(lib.optional (o.settings.HiddenServiceExportCircuitID != null) ''
HiddenServiceExportCircuitID is used in the HiddenService: ${n}
but this option is only for v3 hidden services.
'')
]
++ optionals (o.settings.HiddenServiceVersion != 2) [
(optional (o.settings.HiddenServiceAuthorizeClient != null) ''
++ lib.optionals (o.settings.HiddenServiceVersion != 2) [
(lib.optional (o.settings.HiddenServiceAuthorizeClient != null) ''
HiddenServiceAuthorizeClient is used in the HiddenService: ${n}
but this option is only for v2 hidden services.
'')
(optional (o.settings.RendPostPeriod != null) ''
(lib.optional (o.settings.RendPostPeriod != null) ''
RendPostPeriod is used in the HiddenService: ${n}
but this option is only for v2 hidden services.
'')
@@ -1220,12 +1224,12 @@ in
uid = config.ids.uids.tor;
};
services.tor.settings = mkMerge [
(mkIf cfg.enableGeoIP {
services.tor.settings = lib.mkMerge [
(lib.mkIf cfg.enableGeoIP {
GeoIPFile = "${cfg.package.geoip}/share/tor/geoip";
GeoIPv6File = "${cfg.package.geoip}/share/tor/geoip6";
})
(mkIf cfg.controlSocket.enable {
(lib.mkIf cfg.controlSocket.enable {
ControlPort = [
{
unix = runDir + "/control";
@@ -1234,47 +1238,47 @@ in
}
];
})
(mkIf cfg.relay.enable (
optionalAttrs (cfg.relay.role != "exit") {
ExitPolicy = mkForce [ "reject *:*" ];
(lib.mkIf cfg.relay.enable (
lib.optionalAttrs (cfg.relay.role != "exit") {
ExitPolicy = lib.mkForce [ "reject *:*" ];
}
//
optionalAttrs
(elem cfg.relay.role [
lib.optionalAttrs
(lib.elem cfg.relay.role [
"bridge"
"private-bridge"
])
{
BridgeRelay = true;
ExtORPort.port = mkDefault "auto";
ServerTransportPlugin.transports = mkDefault [ "obfs4" ];
ServerTransportPlugin.exec = mkDefault "${lib.getExe pkgs.obfs4} managed";
ExtORPort.port = lib.mkDefault "auto";
ServerTransportPlugin.transports = lib.mkDefault [ "obfs4" ];
ServerTransportPlugin.exec = lib.mkDefault "${lib.getExe pkgs.obfs4} managed";
}
// optionalAttrs (cfg.relay.role == "private-bridge") {
// lib.optionalAttrs (cfg.relay.role == "private-bridge") {
ExtraInfoStatistics = false;
PublishServerDescriptor = false;
}
))
(mkIf (!cfg.relay.enable) {
(lib.mkIf (!cfg.relay.enable) {
# Avoid surprises when leaving ORPort/DirPort configurations in cfg.settings,
# because it would still enable Tor as a relay,
# which can trigger all sort of problems when not carefully done,
# like the blocklisting of the machine's IP addresses
# by some hosting providers...
DirPort = mkForce [ ];
ORPort = mkForce [ ];
PublishServerDescriptor = mkForce false;
DirPort = lib.mkForce [ ];
ORPort = lib.mkForce [ ];
PublishServerDescriptor = lib.mkForce false;
})
(mkIf (!cfg.client.enable) {
(lib.mkIf (!cfg.client.enable) {
# Make sure application connections via SOCKS are disabled
# when services.tor.client.enable is false
SOCKSPort = mkForce [ 0 ];
SOCKSPort = lib.mkForce [ 0 ];
})
(mkIf cfg.client.enable (
(lib.mkIf cfg.client.enable (
{
SOCKSPort = [ cfg.client.socksListenAddress ];
}
// optionalAttrs cfg.client.transparentProxy.enable {
// lib.optionalAttrs cfg.client.transparentProxy.enable {
TransPort = [
{
addr = "127.0.0.1";
@@ -1282,7 +1286,7 @@ in
}
];
}
// optionalAttrs cfg.client.dns.enable {
// lib.optionalAttrs cfg.client.dns.enable {
DNSPort = [
{
addr = "127.0.0.1";
@@ -1292,8 +1296,8 @@ in
AutomapHostsOnResolve = true;
}
//
optionalAttrs
(flatten (mapAttrsToList (n: o: o.clientAuthorizations) cfg.client.onionServices) != [ ])
lib.optionalAttrs
(lib.flatten (lib.mapAttrsToList (n: o: o.clientAuthorizations) cfg.client.onionServices) != [ ])
{
ClientOnionAuthDir = runDir + "/ClientOnionAuthDir";
}
@@ -1302,15 +1306,20 @@ in
networking.firewall = lib.mkIf cfg.openFirewall {
allowedTCPPorts =
concatMap
lib.concatMap
(
o:
if isInt o && o > 0 then [ o ] else optionals (o ? "port" && isInt o.port && o.port > 0) [ o.port ]
if lib.isInt o && o > 0 then
[ o ]
else
lib.optionals (o ? "port" && lib.isInt o.port && o.port > 0) [ o.port ]
)
(flatten [
cfg.settings.ORPort
cfg.settings.DirPort
]);
(
lib.flatten [
cfg.settings.ORPort
cfg.settings.DirPort
]
);
};
systemd.services.tor = {
@@ -1331,40 +1340,40 @@ in
(
"+"
+ pkgs.writeShellScript "ExecStartPre" (
concatStringsSep "\n" (
flatten (
lib.concatStringsSep "\n" (
lib.flatten (
[ "set -eu" ]
++ mapAttrsToList (
++ lib.mapAttrsToList (
name: onion:
optional (onion.authorizedClients != [ ]) ''
rm -rf ${escapeShellArg onion.path}/authorized_clients
install -d -o tor -g tor -m 0700 ${escapeShellArg onion.path} ${escapeShellArg onion.path}/authorized_clients
lib.optional (onion.authorizedClients != [ ]) ''
rm -rf ${lib.escapeShellArg onion.path}/authorized_clients
install -d -o tor -g tor -m 0700 ${lib.escapeShellArg onion.path} ${lib.escapeShellArg onion.path}/authorized_clients
''
++ imap0 (i: pubKey: ''
++ lib.imap0 (i: pubKey: ''
echo ${pubKey} |
install -o tor -g tor -m 0400 /dev/stdin ${escapeShellArg onion.path}/authorized_clients/${toString i}.auth
install -o tor -g tor -m 0400 /dev/stdin ${lib.escapeShellArg onion.path}/authorized_clients/${toString i}.auth
'') onion.authorizedClients
++ optional (onion.secretKey != null) ''
install -d -o tor -g tor -m 0700 ${escapeShellArg onion.path}
key="$(cut -f1 -d: ${escapeShellArg onion.secretKey} | head -1)"
++ lib.optional (onion.secretKey != null) ''
install -d -o tor -g tor -m 0700 ${lib.escapeShellArg onion.path}
key="$(cut -f1 -d: ${lib.escapeShellArg onion.secretKey} | head -1)"
case "$key" in
("== ed25519v"*"-secret")
install -o tor -g tor -m 0400 ${escapeShellArg onion.secretKey} ${escapeShellArg onion.path}/hs_ed25519_secret_key;;
install -o tor -g tor -m 0400 ${lib.escapeShellArg onion.secretKey} ${lib.escapeShellArg onion.path}/hs_ed25519_secret_key;;
(*) echo >&2 "NixOS does not (yet) support secret key type for onion: ${name}"; exit 1;;
esac
''
) cfg.relay.onionServices
++ mapAttrsToList (
++ lib.mapAttrsToList (
name: onion:
imap0 (
lib.imap0 (
i: prvKeyPath:
let
hostname = removeSuffix ".onion" name;
hostname = lib.removeSuffix ".onion" name;
in
''
printf "%s:" ${escapeShellArg hostname} | cat - ${escapeShellArg prvKeyPath} |
printf "%s:" ${lib.escapeShellArg hostname} | cat - ${lib.escapeShellArg prvKeyPath} |
install -o tor -g tor -m 0700 /dev/stdin \
${runDir}/ClientOnionAuthDir/${escapeShellArg hostname}.${toString i}.auth_private
${runDir}/ClientOnionAuthDir/${lib.escapeShellArg hostname}.${toString i}.auth_private
''
) onion.clientAuthorizations
) cfg.client.onionServices
@@ -1393,9 +1402,9 @@ in
"tor"
"tor/onion"
]
++ flatten (
mapAttrsToList (
name: onion: optional (onion.secretKey == null) "tor/onion/${name}"
++ lib.flatten (
lib.mapAttrsToList (
name: onion: lib.optional (onion.secretKey == null) "tor/onion/${name}"
) cfg.relay.onionServices
);
# The following options are only to optimize:
@@ -1407,10 +1416,10 @@ in
BindPaths = [ stateDir ];
BindReadOnlyPaths =
[
storeDir
builtins.storeDir
"/etc"
]
++ optionals config.services.resolved.enable [
++ lib.optionals config.services.resolved.enable [
"/run/systemd/resolve/stub-resolv.conf"
"/run/systemd/resolve/resolv.conf"
];
@@ -1423,7 +1432,7 @@ in
NoNewPrivileges = true;
PrivateDevices = true;
PrivateMounts = true;
PrivateNetwork = mkDefault false;
PrivateNetwork = lib.mkDefault false;
PrivateTmp = true;
# Tor cannot currently bind privileged port when PrivateUsers=true,
# see https://gitlab.torproject.org/legacy/trac/-/issues/20930
+3 -3
View File
@@ -17,9 +17,9 @@ let
util-linux
busybox
]
++ optional cfg.btrfs.enable btrfs-progs
++ optional cfg.ext4.enable e2fsprogs
++ optional cfg.xfs.enable xfsprogs
++ lib.optional cfg.btrfs.enable btrfs-progs
++ lib.optional cfg.ext4.enable e2fsprogs
++ lib.optional cfg.xfs.enable xfsprogs
++ cfg.extraPackages;
hasFs = fsName: lib.any (fs: fs.fsType == fsName) (lib.attrValues config.fileSystems);
settingsFormat = pkgs.formats.yaml { };
+42 -22
View File
@@ -1,11 +1,14 @@
{ config, lib, pkgs, ... }:
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.earlyoom;
inherit (lib)
concatStringsSep
escapeShellArg
literalExpression
mkDefault
mkEnableOption
@@ -15,7 +18,8 @@ let
mkRemovedOptionModule
optionalString
optionals
types;
types
;
in
{
meta = {
@@ -115,6 +119,11 @@ in
[README](https://github.com/rfjakob/earlyoom#notifications) and
[the man page](https://github.com/rfjakob/earlyoom/blob/master/MANPAGE.md#-n-pathtoscript)
for details.
WARNING: earlyoom is running in a sandbox with ProtectSystem="strict"
by default, so filesystem write is also prohibited for the hook.
If you want to change these protection rules, override the systemd
service via `systemd.services.earlyoom.serviceConfig.ProtectSystem`.
'';
};
@@ -127,8 +136,11 @@ in
extraArgs = mkOption {
type = types.listOf types.str;
default = [];
example = [ "-g" "--prefer '(^|/)(java|chromium)$'" ];
default = [ ];
example = [
"-g"
"--prefer '(^|/)(java|chromium)$'"
];
description = "Extra command-line arguments to be passed to earlyoom.";
};
};
@@ -149,25 +161,33 @@ in
config = mkIf cfg.enable {
services.systembus-notify.enable = mkDefault cfg.enableNotifications;
systemd.packages = [ cfg.package ];
systemd.services.earlyoom = {
description = "Early OOM Daemon for Linux";
overrideStrategy = "asDropin";
wantedBy = [ "multi-user.target" ];
path = optionals cfg.enableNotifications [ pkgs.dbus ];
serviceConfig = {
StandardError = "journal";
ExecStart = concatStringsSep " " ([
"${lib.getExe cfg.package}"
("-m ${toString cfg.freeMemThreshold}"
+ optionalString (cfg.freeMemKillThreshold != null) ",${toString cfg.freeMemKillThreshold}")
("-s ${toString cfg.freeSwapThreshold}"
+ optionalString (cfg.freeSwapKillThreshold != null) ",${toString cfg.freeSwapKillThreshold}")
"-r ${toString cfg.reportInterval}"
]
++ optionals cfg.enableDebugInfo [ "-d" ]
++ optionals cfg.enableNotifications [ "-n" ]
++ optionals (cfg.killHook != null) [ "-N ${escapeShellArg cfg.killHook}" ]
++ cfg.extraArgs);
};
# We setup `EARLYOOM_ARGS` via drop-ins, so disable the default import
# from /etc/default/earlyoom.
serviceConfig.EnvironmentFile = "";
environment.EARLYOOM_ARGS =
lib.cli.toGNUCommandLineShell { } {
m =
"${toString cfg.freeMemThreshold}"
+ optionalString (cfg.freeMemKillThreshold != null) ",${toString cfg.freeMemKillThreshold}";
s =
"${toString cfg.freeSwapThreshold}"
+ optionalString (cfg.freeSwapKillThreshold != null) ",${toString cfg.freeSwapKillThreshold}";
r = "${toString cfg.reportInterval}";
d = cfg.enableDebugInfo;
n = cfg.enableNotifications;
N = if cfg.killHook != null then cfg.killHook else null;
}
+ " "
+ lib.escapeShellArgs cfg.extraArgs;
};
};
}
+26 -3
View File
@@ -9,11 +9,27 @@ let
cfg = config.services.swapspace;
inherit (lib)
types
mkIf
mkOption
mkPackageOption
mkEnableOption
;
configFile = pkgs.writeText "swapspace.conf" (lib.generators.toKeyValue { } cfg.settings);
inherit (pkgs)
makeWrapper
runCommand
writeText
;
configFile = writeText "swapspace.conf" (lib.generators.toKeyValue { } cfg.settings);
userWrapper =
runCommand "swapspace"
{
buildInputs = [ makeWrapper ];
}
''
mkdir -p "$out/bin"
makeWrapper '${lib.getExe cfg.package}' "$out/bin/swapspace" \
--add-flags "-c '${configFile}'"
'';
in
{
options.services.swapspace = {
@@ -28,6 +44,13 @@ in
];
description = "Any extra arguments to pass to swapspace";
};
installWrapper = mkOption {
type = types.bool;
default = true;
description = ''
This will add swapspace wrapped with the generated config, to environment.systemPackages
'';
};
settings = mkOption {
type = types.submodule {
options = {
@@ -92,8 +115,8 @@ in
};
};
config = lib.mkIf cfg.enable {
environment.systemPackages = [ cfg.package ];
config = mkIf cfg.enable {
environment.systemPackages = [ (if cfg.installWrapper then userWrapper else cfg.package) ];
systemd.packages = [ cfg.package ];
systemd.services.swapspace = {
wantedBy = [ "multi-user.target" ];
+3 -3
View File
@@ -15,7 +15,7 @@ let
credentialsFile
else
pkgs.writeText "magnetico-credentials" (
concatStrings (mapAttrsToList (user: hash: "${user}:${hash}\n") cfg.web.credentials)
lib.concatStrings (lib.mapAttrsToList (user: hash: "${user}:${hash}\n") cfg.web.credentials)
);
# default options in magneticod/main.go
@@ -28,7 +28,7 @@ let
crawlerArgs =
with cfg.crawler;
escapeShellArgs (
lib.escapeShellArgs (
[
"--database=${dbURI}"
"--indexer-addr=${address}:${toString port}"
@@ -40,7 +40,7 @@ let
webArgs =
with cfg.web;
escapeShellArgs (
lib.escapeShellArgs (
[
"--database=${dbURI}"
(
+4
View File
@@ -477,6 +477,10 @@ in
};
};
extraConfig = ''
# Frigate wants to connect on 127.0.0.1:5000 for unauthenticated requests
# https://github.com/NixOS/nixpkgs/issues/370349
listen 127.0.0.1:5000;
# vod settings
vod_base_url "";
vod_segments_base_url "";
+1 -1
View File
@@ -152,7 +152,7 @@ in
WorkingDirectory = cfg.stateDir;
ExecStart = ''${cfg.package}/bin/galene \
${optionalString (cfg.insecure) "-insecure"} \
-http ${cfg.httpAddress}:${cfg.httpPort} \
-http ${cfg.httpAddress}:${toString cfg.httpPort} \
-turn ${cfg.turnAddress} \
-data ${cfg.dataDir} \
-groups ${cfg.groupsDir} \
@@ -0,0 +1,98 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.immich-public-proxy;
format = pkgs.formats.json { };
inherit (lib)
types
mkIf
mkOption
mkEnableOption
;
in
{
options.services.immich-public-proxy = {
enable = mkEnableOption "Immich Public Proxy";
package = lib.mkPackageOption pkgs "immich-public-proxy" { };
immichUrl = mkOption {
type = types.str;
description = "URL of the Immich instance";
};
port = mkOption {
type = types.port;
default = 3000;
description = "The port that IPP will listen on.";
};
openFirewall = mkOption {
type = types.bool;
default = false;
description = "Whether to open the IPP port in the firewall";
};
settings = mkOption {
type = types.submodule {
freeformType = format.type;
};
default = { };
description = ''
Configuration for IPP. See <https://github.com/alangrainger/immich-public-proxy/blob/main/README.md#additional-configuration> for options and defaults.
'';
};
};
config = mkIf cfg.enable {
systemd.services.immich-public-proxy = {
description = "Immich public proxy for sharing albums publicly without exposing your Immich instance";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
environment = {
IMMICH_URL = cfg.immichUrl;
IPP_PORT = builtins.toString cfg.port;
IPP_CONFIG = "${format.generate "config.json" cfg.settings}";
};
serviceConfig = {
ExecStart = lib.getExe cfg.package;
SyslogIdentifier = "ipp";
User = "ipp";
Group = "ipp";
DynamicUser = true;
Type = "simple";
Restart = "on-failure";
RestartSec = 3;
# Hardening
CapabilityBoundingSet = "";
NoNewPrivileges = true;
PrivateUsers = true;
PrivateTmp = true;
PrivateDevices = true;
PrivateMounts = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
};
};
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ];
meta.maintainers = with lib.maintainers; [ jaculabilis ];
};
}
+54 -8
View File
@@ -9,18 +9,31 @@ let
cfg = config.services.komga;
inherit (lib) mkOption mkEnableOption maintainers;
inherit (lib.types) port str bool;
settingsFormat = pkgs.formats.yaml { };
in
{
imports = [
(lib.mkRenamedOptionModule
[
"services"
"komga"
"port"
]
[
"services"
"komga"
"settings"
"server"
"port"
]
)
];
options = {
services.komga = {
enable = mkEnableOption "Komga, a free and open source comics/mangas media server";
port = mkOption {
type = port;
default = 8080;
description = "The port that Komga will listen on.";
};
user = mkOption {
type = str;
default = "komga";
@@ -39,10 +52,25 @@ in
description = "State and configuration directory Komga will use.";
};
settings = lib.mkOption {
inherit (settingsFormat) type;
default = { };
defaultText = lib.literalExpression ''
{
server.port = 8080;
}
'';
description = ''
Komga configuration.
See [documentation](https://komga.org/docs/installation/configuration).
'';
};
openFirewall = mkOption {
type = bool;
default = false;
description = "Whether to open the firewall for the port in {option}`services.komga.port`.";
description = "Whether to open the firewall for the port in {option}`services.komga.settings.server.port`.";
};
};
};
@@ -52,6 +80,16 @@ in
inherit (lib) mkIf getExe;
in
mkIf cfg.enable {
assertions = [
{
assertion = (cfg.settings.komga.config-dir or cfg.stateDir) == cfg.stateDir;
message = "You must use the `services.komga.stateDir` option to properly configure `komga.config-dir`.";
}
];
services.komga.settings = {
server.port = lib.mkDefault 8080;
};
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ];
@@ -66,9 +104,17 @@ in
};
};
systemd.tmpfiles.settings."10-komga" = {
${cfg.stateDir}.d = {
inherit (cfg) user group;
};
"${cfg.stateDir}/application.yml"."L+" = {
argument = builtins.toString (settingsFormat.generate "application.yml" cfg.settings);
};
};
systemd.services.komga = {
environment = {
SERVER_PORT = builtins.toString cfg.port;
KOMGA_CONFIGDIR = cfg.stateDir;
};
@@ -374,14 +374,18 @@ in {
type = with types; attrsOf (oneOf [ str int bool ]);
default = {
"pm" = "dynamic";
"pm.max_children" = "32";
"pm.start_servers" = "2";
"pm.min_spare_servers" = "2";
"pm.max_spare_servers" = "4";
"pm.max_children" = "120";
"pm.start_servers" = "12";
"pm.min_spare_servers" = "6";
"pm.max_spare_servers" = "18";
"pm.max_requests" = "500";
};
description = ''
Options for nextcloud's PHP pool. See the documentation on `php-fpm.conf` for details on configuration directives.
Options for nextcloud's PHP pool. See the documentation on `php-fpm.conf` for details on
configuration directives. The above are recommended for a server with 4GiB of RAM.
It's advisable to read the [section about PHPFPM tuning in the upstream manual](https://docs.nextcloud.com/server/30/admin_manual/installation/server_tuning.html#tune-php-fpm)
and consider customizing the values.
'';
};
@@ -416,7 +420,6 @@ in {
config = {
dbtype = mkOption {
type = types.enum [ "sqlite" "pgsql" "mysql" ];
default = "sqlite";
description = "Database type.";
};
dbname = mkOption {
@@ -6,15 +6,20 @@ let
cfg = config.services.xserver.windowManager.dwm;
in
{
in {
###### interface
options = {
services.xserver.windowManager.dwm = {
enable = mkEnableOption "dwm";
extraSessionCommands = mkOption {
default = "";
type = types.lines;
description = ''
Shell commands executed just before dwm is started.
'';
};
package = mkPackageOption pkgs "dwm" {
example = ''
pkgs.dwm.overrideAttrs (oldAttrs: rec {
@@ -30,20 +35,20 @@ in
};
};
###### implementation
config = mkIf cfg.enable {
services.xserver.windowManager.session = singleton
{ name = "dwm";
start =
''
export _JAVA_AWT_WM_NONREPARENTING=1
dwm &
waitPID=$!
'';
};
services.xserver.windowManager.session = singleton {
name = "dwm";
start = ''
${cfg.extraSessionCommands}
export _JAVA_AWT_WM_NONREPARENTING=1
dwm &
waitPID=$!
'';
};
environment.systemPackages = [ cfg.package ];
@@ -544,6 +544,13 @@ sub handle_modified_unit { ## no critic(Subroutines::ProhibitManyArgs, Subroutin
}
}
if (parse_systemd_bool(\%new_unit_info, "Service", "X-NotSocketActivated", 0)) {
# If the unit explicitly opts out of socket
# activation, restart it as if it weren't (but do
# restart its sockets, that's fine):
$socket_activated = 0;
}
# If the unit is not socket-activated, record
# that this unit needs to be started below.
# We write this to a file to ensure that the
@@ -159,7 +159,7 @@ def copy_from_file(file: str, dry_run: bool = False) -> str:
def write_entry(profile: str | None, generation: int, specialisation: str | None,
machine_id: str, bootspec: BootSpec, current: bool) -> None:
machine_id: str | None, bootspec: BootSpec, current: bool) -> None:
if specialisation:
bootspec = bootspec.specialisations[specialisation]
kernel = copy_from_file(bootspec.kernel)
@@ -281,11 +281,7 @@ def install_bootloader(args: argparse.Namespace) -> None:
except IOError as e:
if e.errno != errno.ENOENT:
raise
# Since systemd version 232 a machine ID is required and it might not
# be there on newly installed systems, so let's generate one so that
# bootctl can find it and we can also pass it to write_entry() later.
cmd = [f"{SYSTEMD}/bin/systemd-machine-id-setup", "--print"]
machine_id = run(cmd, stdout=subprocess.PIPE).stdout.rstrip()
machine_id = None
if os.getenv("NIXOS_INSTALL_GRUB") == "1":
warnings.warn("NIXOS_INSTALL_GRUB env var deprecated, use NIXOS_INSTALL_BOOTLOADER", DeprecationWarning)
+1
View File
@@ -2901,6 +2901,7 @@ let
config.environment.etc."systemd/networkd.conf".source
];
aliases = [ "dbus-org.freedesktop.network1.service" ];
notSocketActivated = true;
};
networking.iproute2 = mkIf (cfg.config.addRouteTablesToIPRoute2 && cfg.config.routeTables != { }) {
@@ -88,9 +88,13 @@ in
]
}
pushd $out
tar -Sc $diskImage | gzip -${toString cfg.compressionLevel} > \
# RTFM:
# https://cloud.google.com/compute/docs/images/create-custom
# https://cloud.google.com/compute/docs/import/import-existing-image
mv $diskImage disk.raw
tar -Sc disk.raw | gzip -${toString cfg.compressionLevel} > \
${config.image.fileName}
rm $diskImage
rm disk.raw
popd
'';
format = "raw";
+10 -5
View File
@@ -13,7 +13,12 @@ let
'';
qemuConfigFile = pkgs.writeText "qemu.conf" ''
${optionalString cfg.qemu.ovmf.enable ''
nvram = [ "/run/libvirt/nix-ovmf/AAVMF_CODE.fd:/run/libvirt/nix-ovmf/AAVMF_VARS.fd", "/run/libvirt/nix-ovmf/OVMF_CODE.fd:/run/libvirt/nix-ovmf/OVMF_VARS.fd" ]
nvram = [
"/run/libvirt/nix-ovmf/AAVMF_CODE.fd:/run/libvirt/nix-ovmf/AAVMF_VARS.fd",
"/run/libvirt/nix-ovmf/AAVMF_CODE.ms.fd:/run/libvirt/nix-ovmf/AAVMF_VARS.ms.fd",
"/run/libvirt/nix-ovmf/OVMF_CODE.fd:/run/libvirt/nix-ovmf/OVMF_VARS.fd",
"/run/libvirt/nix-ovmf/OVMF_CODE.ms.fd:/run/libvirt/nix-ovmf/OVMF_VARS.ms.fd"
]
''}
${optionalString (!cfg.qemu.runAsRoot) ''
user = "qemu-libvirtd"
@@ -451,10 +456,10 @@ in
};
in
''
ln -s --force ${ovmfpackage}/FV/AAVMF_CODE.fd /run/${dirName}/nix-ovmf/
ln -s --force ${ovmfpackage}/FV/OVMF_CODE.fd /run/${dirName}/nix-ovmf/
ln -s --force ${ovmfpackage}/FV/AAVMF_VARS.fd /run/${dirName}/nix-ovmf/
ln -s --force ${ovmfpackage}/FV/OVMF_VARS.fd /run/${dirName}/nix-ovmf/
ln -s --force ${ovmfpackage}/FV/AAVMF_CODE{,.ms}.fd /run/${dirName}/nix-ovmf/
ln -s --force ${ovmfpackage}/FV/OVMF_CODE{,.ms}.fd /run/${dirName}/nix-ovmf/
ln -s --force ${ovmfpackage}/FV/AAVMF_VARS{,.ms}.fd /run/${dirName}/nix-ovmf/
ln -s --force ${ovmfpackage}/FV/OVMF_VARS{,.ms}.fd /run/${dirName}/nix-ovmf/
'')}
# Symlink hooks to /var/lib/libvirt
@@ -14,7 +14,7 @@ let
defaultBackend = options.virtualisation.oci-containers.backend.default;
containerOptions =
{ ... }:
{ name, ... }:
{
options = {
@@ -59,6 +59,13 @@ let
example = literalExpression "pkgs.dockerTools.streamLayeredImage {...};";
};
serviceName = mkOption {
type = types.str;
default = "${cfg.backend}-${name}";
defaultText = "<backend>-<name>";
description = "Systemd service name that manages the container";
};
login = {
username = mkOption {
@@ -525,9 +532,7 @@ in
config = lib.mkIf (cfg.containers != { }) (
lib.mkMerge [
{
systemd.services = mapAttrs' (
n: v: nameValuePair "${cfg.backend}-${n}" (mkService n v)
) cfg.containers;
systemd.services = mapAttrs' (n: v: nameValuePair v.serviceName (mkService n v)) cfg.containers;
assertions =
let
+1
View File
@@ -1314,6 +1314,7 @@ in
{
device = "tmpfs";
fsType = "tmpfs";
options = [ "mode=755" ];
}
else
{
@@ -8,6 +8,7 @@ let
inherit (lib)
getExe'
literalExpression
maintainers
mkEnableOption
mkIf
mkOption
@@ -25,7 +26,7 @@ in
];
meta = {
maintainers = [ lib.maintainers.kjeremy ];
maintainers = [ maintainers.kjeremy ];
};
options.virtualisation.vmware.guest = {
+8
View File
@@ -144,6 +144,7 @@ in {
audiobookshelf = handleTest ./audiobookshelf.nix {};
auth-mysql = handleTest ./auth-mysql.nix {};
authelia = handleTest ./authelia.nix {};
auto-cpufreq = handleTest ./auto-cpufreq.nix {};
avahi = handleTest ./avahi.nix {};
avahi-with-resolved = handleTest ./avahi.nix { networkd = true; };
ayatana-indicators = runTest ./ayatana-indicators.nix;
@@ -467,6 +468,7 @@ in {
ifm = handleTest ./ifm.nix {};
iftop = handleTest ./iftop.nix {};
immich = handleTest ./web-apps/immich.nix {};
immich-public-proxy = handleTest ./web-apps/immich-public-proxy.nix {};
incron = handleTest ./incron.nix {};
incus = pkgs.recurseIntoAttrs (handleTest ./incus { lts = false; inherit system pkgs; });
incus-lts = pkgs.recurseIntoAttrs (handleTest ./incus { inherit system pkgs; });
@@ -520,6 +522,7 @@ in {
keyd = handleTest ./keyd.nix {};
keymap = handleTest ./keymap.nix {};
kimai = handleTest ./kimai.nix {};
kmonad = runTest ./kmonad.nix;
knot = handleTest ./knot.nix {};
komga = handleTest ./komga.nix {};
krb5 = discoverTests (import ./krb5);
@@ -658,6 +661,11 @@ in {
navidrome = handleTest ./navidrome.nix {};
nbd = handleTest ./nbd.nix {};
ncdns = handleTest ./ncdns.nix {};
ncps = runTest ./ncps.nix;
ncps-custom-cache-datapath = runTest {
imports = [ ./ncps.nix ];
defaults.services.ncps.cache.dataPath = "/path/to/ncps";
};
ndppd = handleTest ./ndppd.nix {};
nix-channel = pkgs.callPackage ../modules/config/nix-channel/test.nix { };
nebula = handleTest ./nebula.nix {};
+33
View File
@@ -0,0 +1,33 @@
import ./make-test-python.nix (
{ pkgs, ... }:
{
name = "auto-cpufreq-server";
nodes = {
machine =
{ pkgs, ... }:
{
# service will still start but since vm inside qemu cpufreq adjustments
# cannot be made. This will resource in the following error but the service
# remains up:
# ERROR:
# Couldn't find any of the necessary scaling governors.
services.auto-cpufreq = {
enable = true;
settings = {
charger = {
turbo = "auto";
};
};
};
};
};
testScript = ''
machine.start()
machine.wait_for_unit("auto-cpufreq.service")
machine.succeed("auto-cpufreq --force reset")
'';
}
)
+41 -14
View File
@@ -1,16 +1,43 @@
import ./make-test-python.nix ({ lib, ... }: {
name = "earlyoom";
meta = {
maintainers = with lib.maintainers; [ ncfavier AndersonTorres ];
};
machine = {
services.earlyoom = {
enable = true;
import ./make-test-python.nix (
{ lib, ... }:
{
name = "earlyoom";
meta = {
maintainers = with lib.maintainers; [
ncfavier
AndersonTorres
oxalica
];
};
};
testScript = ''
machine.wait_for_unit("earlyoom.service")
'';
})
nodes.machine =
{ pkgs, ... }:
{
# Limit VM resource usage.
virtualisation.memorySize = 1024;
services.earlyoom = {
enable = true;
# Use SIGKILL, or `tail` will catch SIGTERM and exit successfully.
freeMemKillThreshold = 90;
};
systemd.services.testbloat = {
description = "Create a lot of memory pressure";
serviceConfig = {
ExecStart = "${pkgs.coreutils}/bin/tail /dev/zero";
};
};
};
testScript = ''
machine.wait_for_unit("earlyoom.service")
with subtest("earlyoom should kill the bad service"):
machine.fail("systemctl start --wait testbloat.service")
assert machine.get_unit_info("testbloat.service")["Result"] == "signal"
output = machine.succeed('journalctl -u earlyoom.service -b0')
assert 'low memory! at or below SIGKILL limits' in output
'';
}
)
+4 -1
View File
@@ -66,9 +66,12 @@ import ./make-test-python.nix (
# login and store session
machine.log(machine.succeed(f"http --check-status --session=frigate post http://localhost/api/login user=admin password={password}"))
# make authenticated api requested
# make authenticated api request
machine.log(machine.succeed("http --check-status --session=frigate get http://localhost/api/version"))
# make unauthenticated api request
machine.log(machine.succeed("http --check-status get http://localhost:5000/api/version"))
# wait for a recording to appear
machine.wait_for_file("/var/cache/frigate/test@*.mp4")
'';
-1
View File
@@ -36,7 +36,6 @@ let
meta.maintainers = with maintainers; [
aanderse
kolaente
ma27
];
nodes = {
+52
View File
@@ -0,0 +1,52 @@
{ lib, ... }:
{
name = "kmonad";
meta = {
maintainers = with lib.maintainers; [ linj ];
};
nodes = {
machine = {
services.kmonad = {
enable = true;
extraArgs = [
"--log-level=debug"
];
keyboards = {
defaultKbd = {
device = "/dev/input/by-id/vm-default-kbd";
defcfg = {
enable = true;
fallthrough = true;
};
config = ''
(defsrc :name default-src
1)
(deflayer default-layer :source default-src
@T2)
(defalias
T2 2)
'';
};
};
};
# make a determinate symlink to the default vm keyboard for kmonad to use
services.udev.extraRules = ''
ACTION=="add", KERNEL=="event*", SUBSYSTEM=="input", ATTRS{name}=="QEMU Virtio Keyboard", ATTRS{id/product}=="0001", ATTRS{id/vendor}=="0627", SYMLINK+="input/by-id/vm-default-kbd"
'';
};
};
testScript = ''
service_name = "kmonad-defaultKbd"
machine.wait_for_unit(f"{service_name}.service")
with subtest("kmonad is running"):
machine.succeed(f"systemctl status {service_name}")
with subtest("kmonad symlink is created"):
machine.wait_for_file(f"/dev/input/by-id/{service_name}", timeout=5)
'';
}
+1 -1
View File
@@ -8,7 +8,7 @@ import ./make-test-python.nix ({ lib, ... }:
{ pkgs, ... }:
{ services.komga = {
enable = true;
port = 1234;
settings.server.port = 1234;
};
};
+2 -2
View File
@@ -4,11 +4,11 @@
pkgs ? import ../../.. { inherit system config; },
lib ? pkgs.lib,
kernelVersionsToTest ? [
"4.19"
"5.4"
"5.10"
"5.15"
"6.1"
"6.6"
"latest"
],
}:
@@ -33,7 +33,7 @@ let
# systemd in stage 1
raid-sd-stage-1 = {
test = callTest ./systemd-stage-1.nix;
kernelFilter = lib.id;
kernelFilter = lib.filter (v: v != "5.15");
flavour = "raid";
};
thinpool-sd-stage-1 = {
+89
View File
@@ -0,0 +1,89 @@
{
lib,
pkgs,
...
}:
{
name = "ncps";
nodes = {
harmonia = {
services.harmonia = {
enable = true;
signKeyPaths = [
(pkgs.writeText "cache-key" "cache.example.com-1:9FhO0w+7HjZrhvmzT1VlAZw4OSAlFGTgC24Seg3tmPl4gZBdwZClzTTHr9cVzJpwsRSYLTu7hEAQe3ljy92CWg==")
];
settings.priority = 35;
};
networking.firewall.allowedTCPPorts = [ 5000 ];
system.extraDependencies = [ pkgs.emptyFile ];
};
ncps = {
services.ncps = {
enable = true;
cache = {
hostName = "ncps";
secretKeyPath = builtins.toString (
pkgs.writeText "ncps-cache-key" "ncps:dcrGsrku0KvltFhrR5lVIMqyloAdo0y8vYZOeIFUSLJS2IToL7dPHSSCk/fi+PJf8EorpBn8PU7MNhfvZoI8mA=="
);
};
upstream = {
caches = [ "http://harmonia:5000" ];
publicKeys = [
"cache.example.com-1:eIGQXcGQpc00x6/XFcyacLEUmC07u4RAEHt5Y8vdglo="
];
};
};
networking.firewall.allowedTCPPorts = [ 8501 ];
};
client01 = {
nix.settings = {
substituters = lib.mkForce [ "http://ncps:8501" ];
trusted-public-keys = lib.mkForce [
"ncps:UtiE6C+3Tx0kgpP34vjyX/BKK6QZ/D1OzDYX72aCPJg="
];
};
};
};
testScript =
{ nodes, ... }:
let
narinfoName =
(lib.strings.removePrefix "/nix/store/" (
lib.strings.removeSuffix "-empty-file" pkgs.emptyFile.outPath
))
+ ".narinfo";
narinfoNameChars = lib.strings.stringToCharacters narinfoName;
narinfoPath = lib.concatStringsSep "/" [
nodes.ncps.services.ncps.cache.dataPath
"store/narinfo"
(lib.lists.elemAt narinfoNameChars 0)
((lib.lists.elemAt narinfoNameChars 0) + (lib.lists.elemAt narinfoNameChars 1))
narinfoName
];
in
''
start_all()
harmonia.wait_for_unit("harmonia.service")
ncps.wait_for_unit("ncps.service")
client01.wait_until_succeeds("curl -f http://ncps:8501/ | grep '\"hostname\":\"${toString nodes.ncps.services.ncps.cache.hostName}\"' >&2")
client01.succeed("cat /etc/nix/nix.conf >&2")
client01.succeed("nix-store --realise ${pkgs.emptyFile}")
ncps.succeed("cat ${narinfoPath} >&2")
'';
}
+1
View File
@@ -59,6 +59,7 @@ runTest (
services.nextcloud = {
enable = true;
config.dbtype = "sqlite";
datadir = "/var/lib/nextcloud-data";
autoUpdateApps = {
enable = true;
@@ -69,14 +69,13 @@ runTest (
services.postgresql = {
enable = true;
package = pkgs.postgresql_14;
};
systemd.services.postgresql.postStart = pkgs.lib.mkAfter ''
password=$(cat ${config.services.nextcloud.config.dbpassFile})
${config.services.postgresql.package}/bin/psql <<EOF
CREATE ROLE ${adminuser} WITH LOGIN PASSWORD '$password' CREATEDB;
CREATE DATABASE nextcloud;
GRANT ALL PRIVILEGES ON DATABASE nextcloud TO ${adminuser};
ALTER DATABASE nextcloud OWNER to ${adminuser};
EOF
'';
@@ -36,6 +36,8 @@ runTest (
networking.firewall.allowedTCPPorts = [ 9000 ];
environment.systemPackages = [ pkgs.minio-client ];
services.nextcloud.config.dbtype = "sqlite";
services.nextcloud.config.objectstore.s3 = {
enable = true;
bucket = "nextcloud";
+62 -45
View File
@@ -1,5 +1,13 @@
import ./make-test-python.nix (
{ pkgs, ... }:
{ pkgs, lib, ... }:
let
monitorMethods = [
"ebpf"
"proc"
"ftrace"
"audit"
];
in
{
name = "opensnitch";
@@ -7,10 +15,9 @@ import ./make-test-python.nix (
maintainers = [ onny ];
};
nodes = {
server =
{ ... }:
{
nodes =
{
server = {
networking.firewall.allowedTCPPorts = [ 80 ];
services.caddy = {
enable = true;
@@ -19,50 +26,60 @@ import ./make-test-python.nix (
'';
};
};
clientBlocked =
{ ... }:
{
services.opensnitch = {
enable = true;
settings.DefaultAction = "deny";
};
};
clientAllowed =
{ ... }:
{
services.opensnitch = {
enable = true;
settings.DefaultAction = "deny";
rules = {
curl = {
name = "curl";
enabled = true;
action = "allow";
duration = "always";
operator = {
type = "simple";
sensitive = false;
operand = "process.path";
data = "${pkgs.curl}/bin/curl";
}
// (lib.listToAttrs (
map (
m:
lib.nameValuePair "client_blocked_${m}" {
services.opensnitch = {
enable = true;
settings.DefaultAction = "deny";
settings.ProcMonitorMethod = m;
};
}
) monitorMethods
))
// (lib.listToAttrs (
map (
m:
lib.nameValuePair "client_allowed_${m}" {
services.opensnitch = {
enable = true;
settings.DefaultAction = "deny";
settings.ProcMonitorMethod = m;
rules = {
curl = {
name = "curl";
enabled = true;
action = "allow";
duration = "always";
operator = {
type = "simple";
sensitive = false;
operand = "process.path";
data = "${pkgs.curl}/bin/curl";
};
};
};
};
};
};
};
}
) monitorMethods
));
testScript = ''
start_all()
server.wait_for_unit("caddy.service")
server.wait_for_open_port(80)
testScript =
''
start_all()
server.wait_for_unit("caddy.service")
server.wait_for_open_port(80)
''
+ lib.concatLines (
map (m: ''
client_blocked_${m}.wait_for_unit("opensnitchd.service")
client_blocked_${m}.fail("curl http://server")
clientBlocked.wait_for_unit("opensnitchd.service")
clientBlocked.fail("curl http://server")
clientAllowed.wait_for_unit("opensnitchd.service")
clientAllowed.succeed("curl http://server")
'';
client_allowed_${m}.wait_for_unit("opensnitchd.service")
client_allowed_${m}.succeed("curl http://server")
'') monitorMethods
);
}
)
+1 -1
View File
@@ -399,7 +399,7 @@ let
fastly = {
exporterConfig = {
enable = true;
tokenPath = pkgs.writeText "token" "abc123";
environmentFile = pkgs.writeText "fastly-exporter-env" "FASTLY_API_TOKEN=abc123";
};
exporterTest = ''
+5 -2
View File
@@ -1,10 +1,10 @@
import ./make-test-python.nix (
{ pkgs, lib, ... }:
{ lib, ... }:
{
name = "swapspace";
meta = with pkgs.lib.maintainers; {
meta = with lib.maintainers; {
maintainers = [
Luflosi
phanirithvij
@@ -38,6 +38,9 @@ import ./make-test-python.nix (
machine.wait_for_unit("swapspace.service")
machine.wait_for_unit("root-swapfile.swap")
# ensure swapspace wrapper command runs
machine.succeed("swapspace --inspect")
swamp = False
with subtest("swapspace works"):
machine.execute("mkdir /root/memfs")
@@ -0,0 +1,105 @@
import ../make-test-python.nix (
{ pkgs, lib, ... }:
{
name = "immich-public-proxy";
nodes.machine =
{ pkgs, ... }@args:
{
environment.systemPackages = [
pkgs.imagemagick
pkgs.immich-cli
];
services.immich = {
enable = true;
port = 2283;
# disable a lot of features that aren't needed for this test
machine-learning.enable = false;
settings = {
backup.database.enabled = false;
machineLearning.enabled = false;
map.enabled = false;
reverseGeocoding.enabled = false;
metadata.faces.import = false;
newVersionCheck.enabled = false;
notifications.smtp.enabled = false;
};
};
services.immich-public-proxy = {
enable = true;
immichUrl = "http://localhost:2283";
port = 8002;
settings.ipp.responseHeaders."X-NixOS" = "Rules";
};
};
testScript = ''
import json
machine.wait_for_unit("immich-server.service")
machine.wait_for_unit("immich-public-proxy.service")
machine.wait_for_open_port(2283)
machine.wait_for_open_port(8002)
# The proxy should be up
machine.succeed("curl -sf http://localhost:8002")
# Verify the static assets are served
machine.succeed("curl -sf http://localhost:8002/robots.txt")
machine.succeed("curl -sf http://localhost:8002/share/static/style.css")
# Check that the response header in the settings is sent
res = machine.succeed("""
curl -sD - http://localhost:8002 -o /dev/null
""")
assert "x-nixos: rules" in res.lower(), res
# Log in to Immich and create an access key
machine.succeed("""
curl -sf --json '{ "email": "test@example.com", "name": "Admin", "password": "admin" }' http://localhost:2283/api/auth/admin-sign-up
""")
res = machine.succeed("""
curl -sf --json '{ "email": "test@example.com", "password": "admin" }' http://localhost:2283/api/auth/login
""")
token = json.loads(res)['accessToken']
res = machine.succeed("""
curl -sf -H 'Cookie: immich_access_token=%s' --json '{ "name": "API Key", "permissions": ["all"] }' http://localhost:2283/api/api-keys
""" % token)
key = json.loads(res)['secret']
machine.succeed(f"immich login http://localhost:2283/api {key}")
res = machine.succeed("immich server-info")
print(res)
# Upload some blank images to a new album
# If there's only one image, the proxy serves the image directly
machine.succeed("magick -size 800x600 canvas:white /tmp/white.png")
machine.succeed("immich upload -A ' Reproducible Moments ' /tmp/white.png")
machine.succeed("magick -size 800x600 canvas:black /tmp/black.png")
machine.succeed("immich upload -A ' Reproducible Moments ' /tmp/black.png")
res = machine.succeed("immich server-info")
print(res)
# Get the new album id
res = machine.succeed("""
curl -sf -H 'Cookie: immich_access_token=%s' http://localhost:2283/api/albums
""" % token)
album_id = json.loads(res)[0]['id']
# Create a shared link
res = machine.succeed("""
curl -sf -H 'Cookie: immich_access_token=%s' --json '{ "albumId": "%s", "type": "ALBUM" }' http://localhost:2283/api/shared-links
""" % (token, album_id))
share_key = json.loads(res)['key']
# Access the share
machine.succeed("""
curl -sf http://localhost:2283/share/%s
""" % share_key)
# Access the share through the proxy
machine.succeed("""
curl -sf http://localhost:8002/share/%s
""" % share_key)
'';
}
)
+6 -2
View File
@@ -28,7 +28,6 @@
liblo,
libogg,
libpulseaudio,
librdf_raptor,
librdf_rasqal,
libsamplerate,
libsigcxx,
@@ -94,6 +93,12 @@ stdenv.mkDerivation rec {
url = "https://github.com/Ardour/ardour/commit/338cd09a4aa1b36b8095dfc14ab534395f9a4a92.patch?full_index=1";
hash = "sha256-AvV4aLdkfrxPkE4NX2ETSagq4GjEC+sHCEqdcYvL+CY=";
})
# Fix build with boost >= 1.85
(fetchpatch {
url = "https://github.com/Ardour/ardour/commit/f94bde59d740d65e67c5cd13af4d7ea51453aeaa.patch";
hash = "sha256-dGRjkdF3REkANytDR17wIh8J2+AcLFmV4tKZied/OZg=";
})
];
# Ardour's wscript requires git revision and date to be available.
@@ -139,7 +144,6 @@ stdenv.mkDerivation rec {
liblo
libogg
libpulseaudio
librdf_raptor
librdf_rasqal
libsamplerate
libsigcxx
@@ -13,13 +13,13 @@
stdenv.mkDerivation rec {
pname = "ft2-clone";
version = "1.89";
version = "1.93";
src = fetchFromGitHub {
owner = "8bitbubsy";
repo = "ft2-clone";
rev = "v${version}";
hash = "sha256-s2HMzHJB85kLe3TuKH3oFloWUirmbSYDwh298dZlP6M=";
hash = "sha256-B91kLShg3nvOyOlBkLSpTydhUs5yHa+C/OWe8N+MB9c=";
};
nativeBuildInputs = [ cmake ];
+1 -1
View File
@@ -14,7 +14,7 @@ buildPythonApplication rec {
src = fetchFromGitHub {
owner = "manolomartinez";
repo = pname;
rev = "refs/tags/v${version}";
tag = "v${version}";
sha256 = "sha256-o4+tXVJTgT52JyJOC+Glr2cvZjbTaZL8TIsmz+A4vE4=";
};
@@ -14,11 +14,11 @@
stdenv.mkDerivation rec {
pname = "kmetronome";
version = "1.4.0";
version = "1.4.1";
src = fetchurl {
url = "mirror://sourceforge/${pname}/${version}/${pname}-${version}.tar.bz2";
hash = "sha256-51uFAPR0xsY3z9rFc8SdSGu4ae/VzUmC1qC8RGdt48Y=";
hash = "sha256-FJVmSMu0KDoq8DHRxxGyHQQflPCvH1h+WdsV9wcPAPA=";
};
nativeBuildInputs = [
@@ -20,7 +20,7 @@ stdenv.mkDerivation (finalAttrs: {
src = fetchFromGitHub {
owner = "djdiskmachine";
repo = "littlegptracker";
rev = "refs/tags/${finalAttrs.version}";
tag = finalAttrs.version;
hash = "sha256-1uXC5nJ63YguQuNIkuK0yx9lmrMBqw0WdlmCV8o11cE=";
};
@@ -32,7 +32,6 @@
qtnetworkauth,
qttools,
nixosTests,
apple-sdk_11,
}:
stdenv.mkDerivation (finalAttrs: {
@@ -127,9 +126,6 @@ stdenv.mkDerivation (finalAttrs: {
++ lib.optionals stdenv.hostPlatform.isLinux [
alsa-lib
qtwayland
]
++ lib.optionals stdenv.hostPlatform.isDarwin [
apple-sdk_11
];
postInstall =
+1 -1
View File
@@ -24,7 +24,7 @@ pythonPackages.buildPythonApplication rec {
src = fetchFromGitHub {
owner = pname;
repo = pname;
rev = "refs/tags/${version}";
tag = version;
hash = "sha256-3j6IoMi30BQ8WHK4BxbsW+/3XZx7rBFd47EBENa2GiQ=";
};

Some files were not shown because too many files have changed in this diff Show More