first commit

This commit is contained in:
Beyhan Oğur
2026-04-26 21:52:23 +03:00
commit 880f412e2c
2662 changed files with 866266 additions and 0 deletions

34
nix/devshells/default.nix Normal file
View File

@@ -0,0 +1,34 @@
{pkgs}:
pkgs.mkShellNoCC {
name = "bifrost-nix-dev-shell";
packages = with pkgs; [
go_1_26
gopls
gofumpt
air
delve
go-tools
nodejs_24
];
env = {};
shellHook = ''
CACHE_ROOT="''${XDG_CACHE_HOME:-$HOME/.cache}/bifrost"
mkdir -p "$CACHE_ROOT"
export GOPATH="$CACHE_ROOT/go"
export GOBIN="$GOPATH/bin"
export GOMODCACHE="$GOPATH/pkg/mod"
export GOCACHE="$CACHE_ROOT/gocache"
mkdir -p "$GOBIN" "$GOMODCACHE" "$GOCACHE"
export PATH="$PATH:$GOBIN"
export npm_config_prefix="$CACHE_ROOT/npm-global"
mkdir -p "$npm_config_prefix/bin"
export PATH="$PATH:$npm_config_prefix/bin"
'';
}

216
nix/modules/bifrost.nix Normal file
View File

@@ -0,0 +1,216 @@
{
config,
lib,
pkgs,
...
}:
let
inherit (lib) types;
cfg = config.services.bifrost;
settingsFormat = pkgs.formats.json { };
in
{
options = {
services.bifrost = {
enable = lib.mkEnableOption "Bifrost HTTP gateway";
package = lib.mkPackageOption pkgs "bifrost-http" { };
stateDir = lib.mkOption {
type = types.path;
default = "/var/lib/bifrost";
example = "/var/lib/bifrost";
description = "Application data directory (contains config.json and logs).";
};
host = lib.mkOption {
type = types.str;
default = "127.0.0.1";
example = "0.0.0.0";
description = "The host address which the Bifrost HTTP server listens to.";
};
port = lib.mkOption {
type = types.port;
default = 8080;
example = 11111;
description = "Which port the Bifrost HTTP server listens to.";
};
logLevel = lib.mkOption {
type = types.enum [
"debug"
"info"
"warn"
"error"
];
default = "info";
description = "Logger level.";
};
logStyle = lib.mkOption {
type = types.enum [
"json"
"pretty"
];
default = "json";
description = "Logger output style.";
};
settings = lib.mkOption {
type = types.nullOr settingsFormat.type;
default = null;
description = ''
Optional content for `config.json` under `services.bifrost.stateDir`.
If set, the file will be written on service start (overwriting any existing config.json).
If null, Bifrost will use an existing config.json (or bootstrap from environment).
'';
example = {
providers = [
{
name = "openai";
enabled = true;
keys = [
{
name = "default";
value = "env.OPENAI_API_KEY";
}
];
}
];
};
};
environment = lib.mkOption {
type = types.attrsOf types.str;
default = { };
description = "Extra environment variables for Bifrost.";
example = {
OPENAI_API_KEY = "...";
};
};
environmentFile = lib.mkOption {
description = ''
Environment file to be passed to the systemd service.
Useful for passing secrets to the service to prevent them from being
world-readable in the Nix store.
'';
type = lib.types.nullOr lib.types.path;
default = null;
example = "/var/lib/secrets/bifrost.env";
};
openFirewall = lib.mkOption {
type = types.bool;
default = false;
description = ''
Whether to open the firewall for Bifrost.
This adds `services.bifrost.port` to `networking.firewall.allowedTCPPorts`.
'';
};
extraArgs = lib.mkOption {
type = types.listOf types.str;
default = [ ];
description = "Extra CLI arguments passed to bifrost-http.";
example = [
"-some-flag"
"value"
];
};
};
};
config = lib.mkIf cfg.enable {
assertions =
let
stateDirStr = toString cfg.stateDir;
in
[
{
assertion = builtins.dirOf stateDirStr == "/var/lib";
message = "services.bifrost.stateDir must be a direct child of /var/lib (e.g. /var/lib/bifrost) to work with systemd StateDirectory and DynamicUser.";
}
];
systemd.services.bifrost =
let
stateDirStr = toString cfg.stateDir;
stateDirName = builtins.baseNameOf stateDirStr;
configFile =
if cfg.settings == null then null else settingsFormat.generate "bifrost-config.json" cfg.settings;
in
{
description = "Bifrost AI Gateway (bifrost-http)";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
environment = cfg.environment;
preStart = lib.optionalString (configFile != null) ''
install -Dm600 "${configFile}" "${stateDirStr}/config.json"
'';
serviceConfig = {
ExecStart = lib.concatStringsSep " " (
[
(lib.getExe cfg.package)
"-host"
cfg.host
"-port"
(toString cfg.port)
"-app-dir"
stateDirStr
"-log-level"
cfg.logLevel
"-log-style"
cfg.logStyle
]
++ cfg.extraArgs
);
EnvironmentFile = lib.optional (cfg.environmentFile != null) cfg.environmentFile;
WorkingDirectory = cfg.stateDir;
StateDirectory = stateDirName;
RuntimeDirectory = "bifrost";
RuntimeDirectoryMode = "0755";
PrivateTmp = true;
DynamicUser = true;
DevicePolicy = "closed";
LockPersonality = true;
PrivateUsers = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectControlGroups = true;
RestrictNamespaces = true;
RestrictRealtime = true;
SystemCallArchitectures = "native";
UMask = "0077";
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
ProtectClock = true;
ProtectProc = "invisible";
};
};
networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.port ]; };
};
meta.maintainers = [
{
name = "ReStranger";
github = "ReStranger";
}
];
}

View File

@@ -0,0 +1,83 @@
{
pkgs,
inputs,
src,
version,
bifrost-ui,
}:
let
lib = pkgs.lib;
# Bifrost requires Go 1.26 (go.mod/go.work). Force Go 1.26 for buildGoModule.
buildGoModule = pkgs.callPackage "${inputs.nixpkgs}/pkgs/build-support/go/module.nix" {
go = pkgs.go_1_26 or pkgs.go;
};
transportsLocalReplaces = ''
if [ -f transports/go.mod ]; then
cat >> transports/go.mod <<'EOF'
replace github.com/maximhq/bifrost/core => ../core
replace github.com/maximhq/bifrost/framework => ../framework
replace github.com/maximhq/bifrost/plugins/governance => ../plugins/governance
replace github.com/maximhq/bifrost/plugins/compat => ../plugins/compat
replace github.com/maximhq/bifrost/plugins/logging => ../plugins/logging
replace github.com/maximhq/bifrost/plugins/maxim => ../plugins/maxim
replace github.com/maximhq/bifrost/plugins/otel => ../plugins/otel
replace github.com/maximhq/bifrost/plugins/semanticcache => ../plugins/semanticcache
replace github.com/maximhq/bifrost/plugins/telemetry => ../plugins/telemetry
EOF
fi
'';
in
buildGoModule {
pname = "bifrost-http";
inherit version;
inherit src;
modRoot = "transports";
subPackages = [ "bifrost-http" ];
vendorHash = "sha256-Ck1cwv/DYI9EXmp7U2ZSNXlU+Qok8BFn5bcN1Pv7Nmc=";
doCheck = false;
overrideModAttrs = final: prev: {
postPatch = (prev.postPatch or "") + transportsLocalReplaces;
};
env = {
CGO_ENABLED = "1";
};
nativeBuildInputs = with pkgs; [
pkg-config
gcc
];
buildInputs = [ pkgs.sqlite ];
postPatch = transportsLocalReplaces;
preBuild = ''
# Provide UI assets for //go:embed all:ui
rm -rf bifrost-http/ui
mkdir -p bifrost-http/ui
if [ -d "${bifrost-ui}/ui" ]; then
cp -R --no-preserve=mode,ownership,timestamps "${bifrost-ui}/ui/." bifrost-http/ui/
else
printf '%s\n' '<!doctype html><meta charset="utf-8"><title>Bifrost</title>' > bifrost-http/ui/index.html
fi
'';
ldflags = [
"-s"
"-w"
"-X main.Version=${version}"
];
meta = {
mainProgram = "bifrost-http";
description = "Bifrost HTTP gateway";
homepage = "https://github.com/maximhq/bifrost";
license = lib.licenses.asl20;
};
}

View File

@@ -0,0 +1,48 @@
{
pkgs,
src,
version,
}:
pkgs.buildNpmPackage {
pname = "bifrost-ui";
inherit version;
inherit src;
sourceRoot = "source/ui";
npmDepsHash = "sha256-+tI2NUJtpHwvI9sAYMXO7r00Y3Pb1E62ms1ZSd3O0hM=";
# Next's `next/font/google` requires network access at build time.
# Nix builds are sandboxed (no network), so patch the layout to avoid
# fetching Google Fonts.
postPatch = ''
cat > app/layout.tsx <<'EOF'
import "./globals.css"
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<head>
<link rel="dns-prefetch" href="https://getbifrost.ai" />
<link rel="preconnect" href="https://getbifrost.ai" />
</head>
<body className="font-sans antialiased">{children}</body>
</html>
)
}
EOF
'';
# Avoid the upstream build script's copy step (writes outside $PWD).
npmBuildScript = "build-enterprise";
env.NEXT_TELEMETRY_DISABLED = "1";
env.NEXT_DISABLE_ESLINT = "1";
installPhase = ''
runHook preInstall
mkdir -p "$out/ui"
cp -R --no-preserve=mode,ownership,timestamps out/. "$out/ui/"
runHook postInstall
'';
}