Skip to content

feat: magic rollback #135

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
---
name: "Build Packages"
on:
pull_request:
Expand All @@ -23,9 +24,15 @@ jobs:
if: needs.pre-job.outputs.should_skip != 'true'
steps:
- uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: arm64
- uses: cachix/install-nix-action@v31
with:
nix_path: nixpkgs=channel:nixos-unstable
extra_nix_config: |
extra-platforms = aarch64-linux i686-linux
- uses: cachix/cachix-action@v16
with:
name: wires
Expand Down
13 changes: 13 additions & 0 deletions .github/workflows/pr-preview.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
---
name: "PR Preview"
on:
push:
Expand Down Expand Up @@ -35,9 +36,15 @@ jobs:
- uses: actions/checkout@v4
with:
ref: ${{ needs.base-ref.outputs.base-ref }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: arm64
- uses: cachix/install-nix-action@v31
with:
nix_path: nixpkgs=channel:nixos-unstable
extra_nix_config: |
extra-platforms = aarch64-linux i686-linux
- uses: cachix/cachix-action@v16
with:
name: wires
Expand Down Expand Up @@ -74,9 +81,15 @@ jobs:
if: needs.eval-head.outputs.drv != needs.eval-base.outputs.drv
steps:
- uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: arm64
- uses: cachix/install-nix-action@v31
with:
nix_path: nixpkgs=channel:nixos-unstable
extra_nix_config: |
extra-platforms = aarch64-linux i686-linux
- uses: cachix/cachix-action@v16
with:
name: wires
Expand Down
25 changes: 13 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["wire/key_agent", "wire/lib", "wire/cli"]
members = ["wire/agent", "wire/lib", "wire/cli"]
resolver = "2"
package.edition = "2021"
package.version = "0.1.0"
Expand Down
2 changes: 1 addition & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
./nix/shells.nix
./nix/checks.nix
./wire/cli
./wire/key_agent
./wire/agent
./doc
./tests/nix
];
Expand Down
2 changes: 1 addition & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ build-dhat:
cargo build --profile profiling --features dhat-heap
@echo 'dhat binaries in target/profiling'
@echo 'Example:'
@echo 'WIRE_RUNTIME=/nix/store/...-runtime WIRE_KEY_AGENT=/nix/store/...-key_agent-0.1.0 PROJECT/target/profiling/wire apply ...'
@echo 'WIRE_RUNTIME=/nix/store/...-runtime WIRE_AGENT=/nix/store/...-agent-0.1.0 PROJECT/target/profiling/wire apply ...'
9 changes: 8 additions & 1 deletion runtime/evaluate.nix
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ rec {

inspect = {
inherit path;
nodes = builtins.mapAttrs (_: v: v.config.deployment) nodes;
nodes = builtins.mapAttrs (
_: v:
v.config.deployment
// {
# Necessary for the agent so it can know what architecture it should push to
inherit (v.config.nixpkgs.hostPlatform) system;
}
) nodes;
};
}
3 changes: 2 additions & 1 deletion wire/key_agent/Cargo.toml → wire/agent/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "key_agent"
name = "agent"
edition.workspace = true
version.workspace = true

Expand All @@ -8,6 +8,7 @@ tokio = { workspace = true }
anyhow = { workspace = true }
prost = { workspace = true }
nix = { version = "0.29.0", features = ["user"] }
clap = { workspace = true, features = ["derive"] }

[build-dependencies]
prost-build = "0.5"
3 changes: 3 additions & 0 deletions wire/agent/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
prost_build::compile_protos(&["src/models.proto"], &["src/"]).unwrap();
}
26 changes: 26 additions & 0 deletions wire/agent/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
config,
withSystem,
lib,
...
}:
{

flake.packages =
# macos is not supported with the agent
lib.genAttrs (builtins.filter (system: !lib.hasSuffix "darwin" system) config.systems)

(
system:
withSystem system (
{ buildRustProgram, ... }:
{
agent = buildRustProgram {
name = "agent";
pname = "agent";
cargoExtraArgs = "-p agent";
};
}
)
);
}
53 changes: 53 additions & 0 deletions wire/agent/src/cli.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use std::{path::Path, str::FromStr, time::Duration};

use anyhow::bail;
use clap::{Parser, Subcommand};

#[derive(Clone, Eq, PartialEq, Debug)]
pub struct Time(Duration);

#[derive(Subcommand, Debug)]
pub enum Operations {
#[command()]
/// Push keys
PushKeys {
#[arg(short, long)]
/// Total length for the protobuf message
length: usize,
},
#[command()]
/// Initiate magic rollback session
Rollback {
// Waiting period before transitioning to the timeout phase, where the
// agent awaits a response from wire.
//
/// Grace period
grace_period: Time,
// The waiting period to receive a response from wire, if the time
// exceeds the specified value, the agent will initiate a rollback.
/// Waiting period before rolling back
timeout: Time,
/// Store path to known-working system closure, typically the
/// current/previous one.
known_working_closure: Box<Path>,
},
}

impl FromStr for Time {
type Err = anyhow::Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let num: u64 = match s.parse() {
Ok(v) => v,
Err(e) => bail!(e),
};

Ok(Time(Duration::from_secs(num)))
}
}

#[derive(Parser, Debug)]
pub struct Args {
#[command(subcommand)]
pub operation: Operations,
}
4 changes: 4 additions & 0 deletions wire/agent/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub mod cli;
pub mod keys {
include!(concat!(env!("OUT_DIR"), "/agent.rs"));
}
48 changes: 38 additions & 10 deletions wire/key_agent/src/main.rs → wire/agent/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#![deny(clippy::pedantic)]
use agent::keys::Keys;
use clap::Parser;
use nix::unistd::{Group, User};
use prost::Message;
use std::env;
use std::os::unix::fs::PermissionsExt;
use std::path::{Path, PathBuf};
use std::{
Expand All @@ -10,8 +11,9 @@ use std::{
};
use tokio::fs::File;
use tokio::io::AsyncWriteExt;
use tokio::net::UnixListener;

use key_agent::keys::Keys;
mod cli;

fn create_path(key_path: &Path) -> Result<(), anyhow::Error> {
let prefix = key_path.parent().unwrap();
Expand All @@ -20,18 +22,12 @@ fn create_path(key_path: &Path) -> Result<(), anyhow::Error> {
Ok(())
}

#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
async fn push_keys(length: usize) -> Result<(), anyhow::Error> {
let mut stdin = std::io::stdin();
let length: usize = env::args().nth(1).expect("failed to grab arg").parse()?;
let mut msg_buf = vec![0u8; length];

stdin.read_exact(&mut msg_buf)?;

let msg = Keys::decode(&mut Cursor::new(&msg_buf))?;

println!("{msg:?}");

for key in msg.keys {
let path = PathBuf::from(&key.destination);
create_path(&path)?;
Expand Down Expand Up @@ -63,6 +59,38 @@ async fn main() -> Result<(), anyhow::Error> {

println!("Wrote to {file:?}");
}

Ok(())
}

async fn magic_rollback(
grace_period: cli::Time,
timeout: cli::Time,
known_working_closure: Box<Path>,
) -> Result<(), anyhow::Error> {
// NOTE: The default permissions of the socket do seem to be good enough
// (755, rwxr-xr-x), but we may wish to revisit this to set it to 700.
let socket = UnixListener::bind(".wire-agent").unwrap();

loop {
match socket.accept().await {
Ok((stream, _)) => {}
Err(e) => {
println!("accept() encountered an issue: {e}");
}
}
}
}

#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
let args = cli::Args::parse();

match args.operation {
cli::Operations::PushKeys { length } => push_keys(length).await,
cli::Operations::Rollback {
grace_period,
timeout,
known_working_closure,
} => magic_rollback(grace_period, timeout, known_working_closure).await,
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
syntax = "proto3";

package key_agent.keys;

package agent;

message Key {
string destination = 1;
Expand All @@ -13,3 +14,9 @@ message Key {
message Keys {
repeated Key keys = 1;
}


// TODO (opcode signaling and other stuff like logs maybe)
message Rollback {

}
20 changes: 15 additions & 5 deletions wire/cli/default.nix
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
{ self, ... }:
{
perSystem =
{
pkgs,
lib,
self',
buildRustProgram,
...
Expand Down Expand Up @@ -29,11 +31,19 @@
nativeBuildInputs = [
pkgs.makeWrapper
];
postBuild = ''
wrapProgram $out/bin/wire \
--set WIRE_RUNTIME ${../../runtime} \
--set WIRE_KEY_AGENT ${self'.packages.agent}
'';
postBuild =
let
agents = lib.mapAttrsToList (name: value: {
inherit name;
path = value.agent;
}) (lib.filterAttrs (_: value: value ? agent) self.packages);

in
''
wrapProgram $out/bin/wire \
--set WIRE_RUNTIME ${../../runtime} \
--set WIRE_AGENT ${pkgs.linkFarm "wire-agents-farm" agents}
'';
meta.mainProgram = "wire";
};
};
Expand Down
5 changes: 0 additions & 5 deletions wire/key_agent/build.rs

This file was deleted.

Loading
Loading