From 821460ecfb751d4c2b4e02704cc0aa577a850df5 Mon Sep 17 00:00:00 2001
From: Aiden McClelland <me@drbonez.dev>
Date: Thu, 28 Nov 2024 23:24:29 -0700
Subject: [PATCH] wip

---
 core/startos/src/db/model/public.rs           |  1 +
 core/startos/src/registry/package/index.rs    |  1 -
 core/startos/src/s9pk/git_hash.rs             | 29 ++++++++++++++++-
 core/startos/src/s9pk/v2/manifest.rs          |  4 +--
 sdk/base/lib/Effects.ts                       |  5 ++-
 sdk/base/lib/osBindings/GitHash.ts            |  3 ++
 sdk/base/lib/osBindings/IpInfo.ts             |  7 +----
 sdk/base/lib/osBindings/Manifest.ts           |  3 +-
 sdk/base/lib/osBindings/PackageVersionInfo.ts |  3 +-
 sdk/base/lib/osBindings/index.ts              |  1 +
 sdk/package/lib/manifest/setupManifest.ts     | 11 -------
 .../server-specs/server-specs.page.html       | 31 +++++++------------
 .../ui/src/app/services/api/mock-patch.ts     | 17 +++++-----
 13 files changed, 62 insertions(+), 54 deletions(-)
 create mode 100644 sdk/base/lib/osBindings/GitHash.ts

diff --git a/core/startos/src/db/model/public.rs b/core/startos/src/db/model/public.rs
index 410dfa6d1..2b4bfe945 100644
--- a/core/startos/src/db/model/public.rs
+++ b/core/startos/src/db/model/public.rs
@@ -131,6 +131,7 @@ pub struct ServerInfo {
     #[ts(type = "string")]
     pub tor_address: Url,
     #[ts(as = "BTreeMap::<String, NetworkInterfaceInfo>")]
+    #[serde(default)]
     pub network_interfaces: BTreeMap<InternedString, NetworkInterfaceInfo>,
     pub acme: Option<AcmeSettings>,
     #[serde(default)]
diff --git a/core/startos/src/registry/package/index.rs b/core/startos/src/registry/package/index.rs
index 428200165..9973bae7e 100644
--- a/core/startos/src/registry/package/index.rs
+++ b/core/startos/src/registry/package/index.rs
@@ -72,7 +72,6 @@ pub struct PackageVersionInfo {
     pub icon: DataUrl<'static>,
     pub description: Description,
     pub release_notes: String,
-    #[ts(type = "string")]
     pub git_hash: GitHash,
     #[ts(type = "string")]
     pub license: InternedString,
diff --git a/core/startos/src/s9pk/git_hash.rs b/core/startos/src/s9pk/git_hash.rs
index 02f83bf4a..762ef8704 100644
--- a/core/startos/src/s9pk/git_hash.rs
+++ b/core/startos/src/s9pk/git_hash.rs
@@ -1,11 +1,13 @@
 use std::path::Path;
 
 use tokio::process::Command;
+use ts_rs::TS;
 
 use crate::prelude::*;
 use crate::util::Invoke;
 
-#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
+#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, TS)]
+#[ts(type = "string")]
 pub struct GitHash(String);
 
 impl GitHash {
@@ -31,6 +33,31 @@ impl GitHash {
         }
         Ok(GitHash(hash))
     }
+    pub fn load_sync() -> Option<GitHash> {
+        let mut hash = String::from_utf8(
+            std::process::Command::new("git")
+                .arg("rev-parse")
+                .arg("HEAD")
+                .output()
+                .ok()?
+                .stdout,
+        )
+        .ok()?;
+        if !std::process::Command::new("git")
+            .arg("diff-index")
+            .arg("--quiet")
+            .arg("HEAD")
+            .arg("--")
+            .output()
+            .ok()?
+            .status
+            .success()
+        {
+            hash += "-modified";
+        }
+
+        Some(GitHash(hash))
+    }
 }
 
 impl AsRef<str> for GitHash {
diff --git a/core/startos/src/s9pk/v2/manifest.rs b/core/startos/src/s9pk/v2/manifest.rs
index 85f3cd796..187b2dede 100644
--- a/core/startos/src/s9pk/v2/manifest.rs
+++ b/core/startos/src/s9pk/v2/manifest.rs
@@ -62,8 +62,8 @@ pub struct Manifest {
     pub dependencies: Dependencies,
     #[serde(default)]
     pub hardware_requirements: HardwareRequirements,
-    #[serde(default)]
-    #[ts(type = "string | null")]
+    #[ts(optional)]
+    #[serde(default = "GitHash::load_sync")]
     pub git_hash: Option<GitHash>,
     #[serde(default = "current_version")]
     #[ts(type = "string")]
diff --git a/sdk/base/lib/Effects.ts b/sdk/base/lib/Effects.ts
index 00d56cfba..a0eb08d67 100644
--- a/sdk/base/lib/Effects.ts
+++ b/sdk/base/lib/Effects.ts
@@ -8,11 +8,10 @@ import {
   SetHealth,
   BindParams,
   HostId,
-  LanInfo,
+  NetInfo,
   Host,
   ExportServiceInterfaceParams,
   ServiceInterface,
-  ActionRequest,
   RequestActionParams,
   MainStatus,
 } from "./osBindings"
@@ -118,7 +117,7 @@ export type Effects = {
     packageId?: PackageId
     hostId: HostId
     internalPort: number
-  }): Promise<LanInfo>
+  }): Promise<NetInfo>
   /** Removes all network bindings, called in the setupInputSpec */
   clearBindings(options: {
     except: { id: HostId; internalPort: number }[]
diff --git a/sdk/base/lib/osBindings/GitHash.ts b/sdk/base/lib/osBindings/GitHash.ts
new file mode 100644
index 000000000..43f6adde3
--- /dev/null
+++ b/sdk/base/lib/osBindings/GitHash.ts
@@ -0,0 +1,3 @@
+// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
+
+export type GitHash = string
diff --git a/sdk/base/lib/osBindings/IpInfo.ts b/sdk/base/lib/osBindings/IpInfo.ts
index ae8c88d1b..184e72ddf 100644
--- a/sdk/base/lib/osBindings/IpInfo.ts
+++ b/sdk/base/lib/osBindings/IpInfo.ts
@@ -1,8 +1,3 @@
 // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
 
-export type IpInfo = {
-  ipv4Range: string | null
-  ipv4: string | null
-  ipv6Range: string | null
-  ipv6: string | null
-}
+export type IpInfo = string[]
diff --git a/sdk/base/lib/osBindings/Manifest.ts b/sdk/base/lib/osBindings/Manifest.ts
index 8007b565b..2c9a2457e 100644
--- a/sdk/base/lib/osBindings/Manifest.ts
+++ b/sdk/base/lib/osBindings/Manifest.ts
@@ -2,6 +2,7 @@
 import type { Alerts } from "./Alerts"
 import type { Dependencies } from "./Dependencies"
 import type { Description } from "./Description"
+import type { GitHash } from "./GitHash"
 import type { HardwareRequirements } from "./HardwareRequirements"
 import type { ImageConfig } from "./ImageConfig"
 import type { ImageId } from "./ImageId"
@@ -30,6 +31,6 @@ export type Manifest = {
   alerts: Alerts
   dependencies: Dependencies
   hardwareRequirements: HardwareRequirements
-  gitHash: string | null
+  gitHash?: GitHash
   osVersion: string
 }
diff --git a/sdk/base/lib/osBindings/PackageVersionInfo.ts b/sdk/base/lib/osBindings/PackageVersionInfo.ts
index 80481acb3..c71fd5921 100644
--- a/sdk/base/lib/osBindings/PackageVersionInfo.ts
+++ b/sdk/base/lib/osBindings/PackageVersionInfo.ts
@@ -3,6 +3,7 @@ import type { Alerts } from "./Alerts"
 import type { DataUrl } from "./DataUrl"
 import type { DependencyMetadata } from "./DependencyMetadata"
 import type { Description } from "./Description"
+import type { GitHash } from "./GitHash"
 import type { HardwareRequirements } from "./HardwareRequirements"
 import type { MerkleArchiveCommitment } from "./MerkleArchiveCommitment"
 import type { PackageId } from "./PackageId"
@@ -13,7 +14,7 @@ export type PackageVersionInfo = {
   icon: DataUrl
   description: Description
   releaseNotes: string
-  gitHash: string
+  gitHash: GitHash
   license: string
   wrapperRepo: string
   upstreamRepo: string
diff --git a/sdk/base/lib/osBindings/index.ts b/sdk/base/lib/osBindings/index.ts
index 5f0506e39..9ca2b51b8 100644
--- a/sdk/base/lib/osBindings/index.ts
+++ b/sdk/base/lib/osBindings/index.ts
@@ -90,6 +90,7 @@ export { GetSslKeyParams } from "./GetSslKeyParams"
 export { GetStatusParams } from "./GetStatusParams"
 export { GetStoreParams } from "./GetStoreParams"
 export { GetSystemSmtpParams } from "./GetSystemSmtpParams"
+export { GitHash } from "./GitHash"
 export { Governor } from "./Governor"
 export { Guid } from "./Guid"
 export { HardwareRequirements } from "./HardwareRequirements"
diff --git a/sdk/package/lib/manifest/setupManifest.ts b/sdk/package/lib/manifest/setupManifest.ts
index c529f1ab7..2db2cc839 100644
--- a/sdk/package/lib/manifest/setupManifest.ts
+++ b/sdk/package/lib/manifest/setupManifest.ts
@@ -27,16 +27,6 @@ export function setupManifest<
   return manifest
 }
 
-function gitHash(): string {
-  const hash = execSync("git rev-parse HEAD").toString().trim()
-  try {
-    execSync("git diff-index --quiet HEAD --")
-    return hash
-  } catch (e) {
-    return hash + "-modified"
-  }
-}
-
 export function buildManifest<
   Id extends string,
   Version extends string,
@@ -67,7 +57,6 @@ export function buildManifest<
   )
   return {
     ...manifest,
-    gitHash: gitHash(),
     osVersion: SDKVersion,
     version: versions.current.options.version,
     releaseNotes: versions.current.options.releaseNotes,
diff --git a/web/projects/ui/src/app/pages/server-routes/server-specs/server-specs.page.html b/web/projects/ui/src/app/pages/server-routes/server-specs/server-specs.page.html
index 03d7ef3d7..1ea8f8a79 100644
--- a/web/projects/ui/src/app/pages/server-routes/server-specs/server-specs.page.html
+++ b/web/projects/ui/src/app/pages/server-routes/server-specs/server-specs.page.html
@@ -58,25 +58,18 @@ <h2>LAN</h2>
         <ion-icon slot="icon-only" name="copy-outline"></ion-icon>
       </ion-button>
     </ion-item>
-    <ng-container *ngFor="let iface of server.ipInfo| keyvalue">
-      <ion-item *tuiLet="iface.value.ipv4 as ipv4">
-        <ion-label>
-          <h2>{{ iface.key }} (IPv4)</h2>
-          <p>{{ ipv4 || 'n/a' }}</p>
-        </ion-label>
-        <ion-button *ngIf="ipv4" slot="end" fill="clear" (click)="copy(ipv4)">
-          <ion-icon slot="icon-only" name="copy-outline"></ion-icon>
-        </ion-button>
-      </ion-item>
-      <ion-item *tuiLet="iface.value.ipv6 as ipv6">
-        <ion-label>
-          <h2>{{ iface.key }} (IPv6)</h2>
-          <p>{{ ipv6 || 'n/a' }}</p>
-        </ion-label>
-        <ion-button *ngIf="ipv6" slot="end" fill="clear" (click)="copy(ipv6)">
-          <ion-icon slot="icon-only" name="copy-outline"></ion-icon>
-        </ion-button>
-      </ion-item>
+    <ng-container *ngFor="let iface of server.networkInterfaces | keyvalue">
+      <ng-container *ngFor="let ipnet of iface.value.ipInfo">
+        <ion-item *tuiLet="ipnet.split('/')[0] as ipAddr">
+          <ion-label>
+            <h2>{{ iface.key }} ({{ ipAddr.includes("::") ? "IPv6" : "IPv4" }})</h2>
+            <p>{{ ipAddr }}</p>
+          </ion-label>
+          <ion-button slot="end" fill="clear" (click)="copy(ipAddr)">
+            <ion-icon slot="icon-only" name="copy-outline"></ion-icon>
+          </ion-button>
+        </ion-item>
+      </ng-container>
     </ng-container>
 
     <ion-item-divider>Device Credentials</ion-item-divider>
diff --git a/web/projects/ui/src/app/services/api/mock-patch.ts b/web/projects/ui/src/app/services/api/mock-patch.ts
index aea6b5828..a6a86e0fc 100644
--- a/web/projects/ui/src/app/services/api/mock-patch.ts
+++ b/web/projects/ui/src/app/services/api/mock-patch.ts
@@ -42,18 +42,17 @@ export const mockPatchData: DataModel = {
     lastBackup: new Date(new Date().valueOf() - 604800001).toISOString(),
     lanAddress: 'https://adjective-noun.local',
     torAddress: 'https://myveryownspecialtoraddress.onion',
-    ipInfo: {
+    networkInterfaces: {
       eth0: {
-        ipv4: '10.0.0.1',
-        ipv4Range: '10.0.0.1/24',
-        ipv6: null,
-        ipv6Range: null,
+        public: false,
+        ipInfo: ['10.0.0.1/24'],
       },
       wlan0: {
-        ipv4: '10.0.90.12',
-        ipv4Range: '10.0.90.12/24',
-        ipv6: 'FE80:CD00:0000:0CDE:1257:0000:211E:729CD',
-        ipv6Range: 'FE80:CD00:0000:0CDE:1257:0000:211E:729CD/64',
+        public: false,
+        ipInfo: [
+          '10.0.90.12/24',
+          'FE80:CD00:0000:0CDE:1257:0000:211E:729CD/64',
+        ],
       },
     },
     acme: null,