Merge v3-t103: seed /srv/www as one folder userland/web/www, whole-folder copy, Nix check for GET / (T103, D70)
This commit is contained in:
+4
-2
@@ -53,6 +53,8 @@ Coreutils, diffutils, procps, and brush each occupy one real binary in `bin/`.
|
||||
Their command names are relative symlinks to those binaries.
|
||||
The world copier preserves these symlinks and dangling links in the source tree.
|
||||
A fresh development world needs no manual source copy.
|
||||
Both bundle builders copy `userland/web/www/` whole into `/srv/www/`, with the original filenames and the Marked license.
|
||||
The server crate, service unit, and test scripts stay outside that folder.
|
||||
The bundle includes `/bin/web.wasm` and an enabled `/etc/systemd/system/web.service`.
|
||||
World init starts that service on `0.0.0.0:8080`.
|
||||
To change its address, edit `ExecStart` to add `--listen ADDR`, then run `systemctl restart web` inside the world.
|
||||
@@ -166,8 +168,8 @@ node userland/web/browser-check.mjs
|
||||
The script uses agent-browser and a CDP virtual authenticator. It registers a passkey and approves an item creation request.
|
||||
Set `AGENT_BROWSER_EXECUTABLE_PATH` if Chrome needs an explicit path.
|
||||
|
||||
Sources: [`host API`](../host/src/api/README.md), [`credential views`](../userland/web/credentials-view.js),
|
||||
[`edits.rs`](../host/src/cred/edits.rs), and [`browser cryptography`](../userland/web/credentials.js).
|
||||
Sources: [`host API`](../host/src/api/README.md), [`credential views`](../userland/web/www/credentials-view.js),
|
||||
[`edits.rs`](../host/src/cred/edits.rs), and [`browser cryptography`](../userland/web/www/credentials.js).
|
||||
|
||||
## Models
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
cp -R ${./config/roster} $out/etc/sausage/roster
|
||||
cp ${./userland/web/web.service} $out/etc/systemd/system/web.service
|
||||
touch $out/etc/systemd/system/multi-user.target.wants/web.service
|
||||
cp ${./userland/web/index.html} ${./userland/web/credentials.js} ${./userland/web/credentials-view.js} $out/srv/www/
|
||||
cp -R ${./userland/web/www}/. $out/srv/www/
|
||||
'';
|
||||
sausageUnwrapped = craneLib.buildPackage (hostArgs // {
|
||||
cargoArtifacts = hostArtifacts;
|
||||
@@ -200,6 +200,13 @@
|
||||
test -f "$TMPDIR/world/world/etc/sausage/roster/sausage.md"
|
||||
touch $out
|
||||
'';
|
||||
checks.web = pkgs.runCommand "sausage-web-seed" {
|
||||
nativeBuildInputs = [ pkgs.nushell pkgs.curl ];
|
||||
} ''
|
||||
export SAUSAGE_CACHE="$TMPDIR/sausage-cache"
|
||||
nu ${./userland/web/seed-check.nu} ${sausage}/bin/sausage ${bundle}
|
||||
touch $out
|
||||
'';
|
||||
apps.default = { type = "app"; program = "${sausage}/bin/sausage"; };
|
||||
devShells.default = pkgs.mkShell (v8Env // wasiCcEnv // moldEnv // {
|
||||
packages = [ rust pkgs.wasmtime pkgs.openssl pkgs.pkg-config pkgs.go pkgs.cmake pkgs.llvmPackages_21.lld ] ++ builderTools ++ mold;
|
||||
|
||||
@@ -309,7 +309,7 @@ async fn approvals_registration_and_revocation() -> Result<()> {
|
||||
|
||||
async fn encrypt(_api: &Api, public_key: Value) -> Result<Envelope> {
|
||||
use deno_core::{JsRuntime, RuntimeOptions};
|
||||
let script = include_str!("../../../userland/web/credentials.js");
|
||||
let script = include_str!("../../../userland/web/www/credentials.js");
|
||||
let mut runtime = JsRuntime::new(RuntimeOptions {
|
||||
extensions: vec![
|
||||
deno_webidl::deno_webidl::init(),
|
||||
|
||||
@@ -42,7 +42,7 @@ fn empty_rule_summary() -> anyhow::Result<()> {
|
||||
#[test]
|
||||
fn page_rendering() -> anyhow::Result<()> {
|
||||
let source = Path::new(env!("CARGO_MANIFEST_DIR")).join("../userland/web");
|
||||
let page = std::fs::read_to_string(source.join("index.html"))?;
|
||||
let page = std::fs::read_to_string(source.join("www/index.html"))?;
|
||||
let script = page
|
||||
.split_once("<script>")
|
||||
.unwrap()
|
||||
@@ -120,11 +120,7 @@ async fn seeded_chat_case(open_connection: bool) -> anyhow::Result<()> {
|
||||
&bundle.path().join("src/sausage/userland/web"),
|
||||
)?;
|
||||
let www = bundle.path().join("srv/www");
|
||||
std::fs::create_dir_all(&www)?;
|
||||
std::fs::copy(
|
||||
source.join("userland/web/index.html"),
|
||||
www.join("index.html"),
|
||||
)?;
|
||||
crate::common::copy_tree(&source.join("userland/web/www"), &www)?;
|
||||
let dir = tempfile::tempdir()?;
|
||||
drop(World::open_with_userland(dir.path(), Some(bundle.path()))?);
|
||||
let port = std::net::TcpListener::bind("127.0.0.1:0")?
|
||||
|
||||
+1
-1
@@ -115,7 +115,7 @@ impl Browser {
|
||||
item["fields"][0]["field_id"].as_str().unwrap()
|
||||
);
|
||||
let public = self.json("GET", "/cred/entry/key", Value::Null)?;
|
||||
let script = include_str!("../../../userland/web/credentials.js");
|
||||
let script = include_str!("../../../userland/web/www/credentials.js");
|
||||
let mut runtime = deno_core::JsRuntime::new(deno_core::RuntimeOptions {
|
||||
extensions: vec![
|
||||
deno_webidl::deno_webidl::init(),
|
||||
|
||||
+2
-6
@@ -40,12 +40,8 @@ def main [destination?: path] {
|
||||
mkdir ($units | path join multi-user.target.wants)
|
||||
let www = ($destination | path join srv www)
|
||||
mkdir $www
|
||||
^cp --remove-destination ($here | path join web index.html) ($www | path join index.html)
|
||||
if $env.LAST_EXIT_CODE != 0 { error make {msg: 'web page copy failed'} }
|
||||
for file in [credentials.js credentials-view.js] {
|
||||
^cp --remove-destination ($here | path join web $file) ($www | path join $file)
|
||||
if $env.LAST_EXIT_CODE != 0 { error make {msg: 'credential UI copy failed'} }
|
||||
}
|
||||
^cp -R --remove-destination ($here | path join web www .) $www
|
||||
if $env.LAST_EXIT_CODE != 0 { error make {msg: 'web folder copy failed'} }
|
||||
^cp --remove-destination ($here | path join web web.service) ($units | path join web.service)
|
||||
if $env.LAST_EXIT_CODE != 0 { error make {msg: 'web unit copy failed'} }
|
||||
'' | save --force ($units | path join multi-user.target.wants web.service)
|
||||
|
||||
@@ -67,7 +67,7 @@ assert.equal(run("requestSummary('Give access to 1 credential items for 1 hour.'
|
||||
assert.equal(run("requestSummary('Give access to 11 credential items for 1 hour.')"),'Give access to 11 credential items for 1 hour.');
|
||||
context.conversations=[{id:1,agent:null},{id:24,agent:null},{id:25,agent:{}},{id:14,agent:{model:{provider:'faux'}}}];
|
||||
assert.equal(run('visibleConversations(conversations).map(c=>c.id).join()'),'1,14');
|
||||
vm.runInContext(fs.readFileSync(__dirname+'/credentials-view.js','utf8').split('const credentialView=')[0],context);
|
||||
vm.runInContext(fs.readFileSync(__dirname+'/www/credentials-view.js','utf8').split('const credentialView=')[0],context);
|
||||
const config={id:'one',name:'Example <item>',rules:[{scheme:'https',hosts:['api.example.com'],port:443,path_prefixes:['/v1'],methods:['GET']}],fields:[{name:'token',public:false,field_type:'text'}],transform_js:'present'};
|
||||
context.review={summary:'Create item',subject:{kind:'program',id:'/bin/curl'},payload:{create:config}};
|
||||
context.items=[config];
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env nu
|
||||
# Check the packaged seed through its web service without configured providers.
|
||||
def main [host: path, bundle: path] {
|
||||
let world = ($env.TMPDIR | path join web-world)
|
||||
^$host init $world
|
||||
if $env.LAST_EXIT_CODE != 0 { error make {msg: 'seed init failed'} }
|
||||
'providers: {}' | save --force ($world | path join world etc sausage config.yaml)
|
||||
let server = (job spawn {
|
||||
'' | ^$host run $world out> server.stdout err> server.stderr
|
||||
})
|
||||
try {
|
||||
let deadline = (date now) + 60sec
|
||||
loop {
|
||||
let response = (^curl --silent --show-error --noproxy '*' --max-time 2 --output whoami.json --write-out '%{http_code}' http://127.0.0.1:8080/api/whoami | complete)
|
||||
if $response.exit_code == 0 and $response.stdout == '200' { break }
|
||||
if (date now) >= $deadline { error make {msg: $'GET /api/whoami did not return 200: ($response)'} }
|
||||
}
|
||||
let response = (^curl --silent --show-error --noproxy '*' --max-time 5 --output page.html --write-out '%{http_code}' http://127.0.0.1:8080/ | complete)
|
||||
if $response.exit_code != 0 or $response.stdout != '200' {
|
||||
error make {msg: $'GET / expected 200, received ($response.stdout): ($response.stderr)'}
|
||||
}
|
||||
if not (open --raw page.html | str contains 'Sausage chat') { error make {msg: 'GET / did not return the chat page'} }
|
||||
let paths = (^find $bundle -printf '%P\n' | complete)
|
||||
if $paths.exit_code != 0 { error make {msg: $paths.stderr} }
|
||||
if ($paths.stdout | lines | any {|path| $path =~ '(^|/)[0-9a-z]{32}-' }) {
|
||||
error make {msg: 'a bundle path has a Nix store hash prefix'}
|
||||
}
|
||||
} catch {|err|
|
||||
job kill $server
|
||||
print --stderr (open --raw server.stderr)
|
||||
error make {msg: $err.msg}
|
||||
}
|
||||
job kill $server
|
||||
print 'PASS packaged seed: GET /, GET /api/whoami, and unprefixed paths'
|
||||
}
|
||||
Reference in New Issue
Block a user