Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
15 changes: 5 additions & 10 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
# Encryption keys used during build
CRYPTO_KEY=
MAGIC_IV=
MAGIC_SALT=
NEW_CRYPTO_KEY=

# Core API endpoints
NEW_DRIVE_URL=
DRIVE_API_URL=
PAYMENTS_URL=
INTERNXT_DESKTOP_HEADER_KEY=

BRIDGE_URL=
APP_SEGMENT_KEY=
APP_SEGMENT_KEY_TEST=
BUG_REPORTING_URL=
PAYMENTS_URL=
NOTIFICATIONS_URL=
LOCK_REFRESH_INTERVAL=

RUDDERSTACK_KEY=
RUDDERSTACK_DATA_PLANE_URL=
# Desktop client identification
INTERNXT_DESKTOP_HEADER_KEY=
4 changes: 3 additions & 1 deletion .erb/configs/webpack.config.main.prod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,13 @@ const configuration: webpack.Configuration = {
},

optimization: {
chunkIds: 'deterministic',
minimizer: [
new TerserPlugin({
parallel: true,
parallel: false,
}),
],
moduleIds: 'deterministic',
Comment on lines 40 to +47
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why these changes are necessary?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Parallelism in TerserPlugin (parallel: false) was disabled to guarantee reproducible builds and avoid hash/code variations between runs on different environments or hardware. Parallel minification can introduce subtle differences due to non-deterministic processing order.
  • The flags chunkIds: 'deterministic' and moduleIds: 'deterministic' were added in the optimization section to ensure chunk and module names remain stable across builds, making integrity verification and release debugging easier.
  • These decisions are driven by the need for 100% reproducible binary builds in CI/CD and to facilitate release auditing and traceability.

},

plugins: [
Expand Down
8 changes: 6 additions & 2 deletions .erb/configs/webpack.config.renderer.prod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,17 @@ const configuration: webpack.Configuration = {
},

optimization: {
chunkIds: 'deterministic',
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true,
parallel: false,
}),
new CssMinimizerPlugin({
parallel: false,
}),
new CssMinimizerPlugin(),
],
moduleIds: 'deterministic',
},

plugins: [
Expand Down
121 changes: 93 additions & 28 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,21 @@ on:
release:
types: [published]
workflow_dispatch:
inputs:
publish_to_github:
description: "Publish artifacts to GitHub release"
required: true
default: "false"
type: choice
options:
- "false"
- "true"

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
packages: write
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'

- name: Create .npmrc file
run: |
echo "@internxt:registry=https://npm.pkg.github.com/" > .npmrc
echo "//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}" >> .npmrc

- name: Install rpm build tools
run: sudo apt-get install -y rpm

- name: Install dependencies
run: npm ci

- name: Add .env
run: |
Expand All @@ -37,18 +28,92 @@ jobs:
echo "MAGIC_SALT=${{ secrets.MAGIC_SALT }}" >> .env
echo "NEW_CRYPTO_KEY=${{ secrets.NEW_CRYPTO_KEY }}" >> .env
echo "NEW_DRIVE_URL=https://gateway.internxt.com/drive" >> .env
echo "DRIVE_API_URL=https://gateway.internxt.com/api" >> .env
echo "PAYMENTS_URL=https://gateway.internxt.com/payments" >> .env
echo "INTERNXT_DESKTOP_HEADER_KEY=${{ secrets.INTERNXT_DESKTOP_HEADER_KEY }}" >> .env
echo "BRIDGE_URL=https://gateway.internxt.com/network" >> .env
echo "APP_SEGMENT_KEY=${{ secrets.APP_SEGMENT_KEY }}" >> .env
echo "APP_SEGMENT_KEY_TEST=${{ secrets.APP_SEGMENT_KEY_TEST }}" >> .env
echo "BUG_REPORTING_URL=https://desktop-bug-reporting.inxt.workers.dev" >> .env
echo "NOTIFICATIONS_URL=https://notifications.internxt.com" >> .env
echo "LOCK_REFRESH_INTERVAL=20000" >> .env

- name: Build app
run: npm run build
- name: Build release container image
run: docker build -f Dockerfile.release -t internxt-release-builder:24.04 .

- name: Build app inside container
run: |
docker run --rm \
-e CI=true \
-v "$PWD:/workspace" \
-w /workspace \
internxt-release-builder:24.04 \
bash -lc './scripts/run-release-build-in-container.sh'

- name: Upload artifacts for smoke tests
if: success()
uses: actions/upload-artifact@v4
with:
name: linux-release-artifacts
path: |
build/*.AppImage
build/*.deb
build/*.rpm
build/*.yml

- name: Upload build metadata
if: always()
uses: actions/upload-artifact@v4
with:
name: build-metadata
path: |
build-manifest.json
build-checksums.txt

smoke-test-deb:
needs: build
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04, ubuntu-latest]
steps:
- name: Download release artifacts
uses: actions/download-artifact@v4
with:
name: linux-release-artifacts
path: build

- name: Install runtime dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends xvfb

- name: Publish app
run: npm run publish
- name: Install deb package for smoke test
run: |
sudo dpkg -i --force-depends build/*.deb
test -x /opt/Internxt/internxt

- name: Start app in headless mode
run: |
xvfb-run -a /opt/Internxt/internxt --no-sandbox --version &
APP_PID=$!
sleep 5 # Allow app to initialize
kill $APP_PID

publish-release:
needs: smoke-test-deb
if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && inputs.publish_to_github == 'true' && startsWith(github.ref, 'refs/tags/')) }}
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- name: Download tested artifacts
uses: actions/download-artifact@v4
with:
name: linux-release-artifacts
path: build

- name: Publish tested artifacts to GitHub release
uses: softprops/action-gh-release@v2
with:
files: |
build/*.AppImage
build/*.deb
build/*.rpm
build/*.yml
2 changes: 1 addition & 1 deletion .github/workflows/sonar-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y libfuse2 libgtk-3-0 libnotify4 libnss3 libxss1 libxtst6 xdg-utils libatspi2.0-0 libdrm2 libgbm1 libasound2t64
sudo apt-get install -y libgtk-3-0 libnotify4 libnss3 libxss1 libxtst6 xdg-utils libatspi2.0-0 libdrm2 libgbm1 libasound2t64

- name: Install dependencies
run: npm ci --ignore-scripts
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y libfuse2 libgtk-3-0 libnotify4 libnss3 libxss1 libxtst6 xdg-utils libatspi2.0-0 libdrm2 libgbm1 libasound2t64
sudo apt-get install -y libgtk-3-0 libnotify4 libnss3 libxss1 libxtst6 xdg-utils libatspi2.0-0 libdrm2 libgbm1 libasound2t64

- name: Install dependencies
run: npm ci --ignore-scripts
Expand Down
37 changes: 37 additions & 0 deletions Dockerfile.release
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
FROM ubuntu:24.04

ARG DEBIAN_FRONTEND=noninteractive
ARG NODE_VERSION=20.20.2
ARG GO_VERSION=1.26.1

ENV LANG=C.UTF-8 \
LC_ALL=C.UTF-8 \
NODE_ENV=production

RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
curl \
build-essential \
git \
make \
pkg-config \
python3 \
rpm \
xz-utils \
&& rm -rf /var/lib/apt/lists/*

RUN curl -fsSL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz" -o /tmp/node.tar.xz \
&& mkdir -p /usr/local/node \
&& tar -xJf /tmp/node.tar.xz -C /usr/local/node --strip-components=1 \
&& ln -s /usr/local/node/bin/node /usr/local/bin/node \
&& ln -s /usr/local/node/bin/npm /usr/local/bin/npm \
&& ln -s /usr/local/node/bin/npx /usr/local/bin/npx \
&& rm /tmp/node.tar.xz

RUN curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" -o /tmp/go.tar.gz \
&& rm -rf /usr/local/go \
&& tar -C /usr/local -xzf /tmp/go.tar.gz \
&& ln -s /usr/local/go/bin/go /usr/local/bin/go \
&& rm /tmp/go.tar.gz

WORKDIR /workspace
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,26 @@ Building the `.rpm` package requires `rpmbuild`. On Ubuntu or Debian, install th
sudo apt-get install rpm
```

### Official Release Build (CI Container)

The official release pipeline builds and publishes artifacts inside a pinned container image (`Dockerfile.release`) to reduce host drift.

Current release flow:

1. Build container image from `ubuntu:24.04`.
2. Run `npm ci` and `npm run publish` inside the container.
3. Upload generated artifacts (`.deb`, `.rpm`, `.AppImage`) plus build metadata.
4. Run smoke tests on the generated `.deb` without rebuilding it.

### Smoke Test Strategy

The release workflow includes a smoke test job that:

1. Downloads the previously built `.deb` artifact.
2. Installs runtime dependencies for Linux GUI startup checks.
3. Installs the package and verifies `/opt/Internxt/internxt` exists.
4. Launches the binary in headless mode (`xvfb-run`) and checks startup.

## Login Configuration Using Deeplink

Create a script in the root of the project named `enable-sso.sh` and add the following content:
Expand Down
10 changes: 10 additions & 0 deletions beforeBuild.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ module.exports = async (context) => {
// this, prebuild-install downloads an Electron-v116 prebuilt compiled for
// Electron 24 (V8 11.0) which segfaults under Electron 25+ (V8 11.4).
process.env.npm_config_build_from_source = 'true';
console.log(
JSON.stringify({
tag: 'ELECTRON_REBUILD',
appDir,
arch,
electronVersion,
nodeVersion: process.version,
buildFromSource: process.env.npm_config_build_from_source,
}),
);
await electronRebuild.rebuild({ buildPath: appDir, electronVersion, arch, force: true });

return false;
Expand Down
13 changes: 7 additions & 6 deletions env.d.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
declare global {
namespace NodeJS {
interface ProcessEnv {
// Encryption keys for backups and data protection
CRYPTO_KEY: string;
MAGIC_IV: string;
MAGIC_SALT: string;
NEW_CRYPTO_KEY: string;

// Core API endpoints
NEW_DRIVE_URL: string;
BRIDGE_URL: string;
APP_SEGMENT_KEY: string;
APP_SEGMENT_KEY_TEST: string;
BUG_REPORTING_URL: string;
platform: string;
PAYMENTS_URL: string;
NOTIFICATIONS_URL: string;
LOCK_REFRESH_INTERVAL: string;
DRIVE_API_URL: string;
INTERNXT_DESKTOP_HEADER_KEY: string;
ENABLE_ANTIVIRUS?: string;
NODE_ENV?: string;
PORT?: string;
}
}
}
Expand Down
13 changes: 6 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
},
"scripts": {
"build": "concurrently \"npm run build:main\" \"npm run build:renderer\" \"npm run build:daemon\"",
"build:daemon": "cd packages/fuse-daemon && go build -ldflags='-s -w' -o ../../dist/fuse-daemon ./cmd/daemon",
"build:daemon": "make -C packages/fuse-daemon build",
"build:main": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.main.prod.ts",
"build:renderer": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.prod.ts",
"rebuild": "electron-rebuild --parallel --types prod,dev,optional --module-dir .",
Expand Down Expand Up @@ -74,7 +74,6 @@
},
"deb": {
"depends": [
"libfuse2",
"python3-nautilus"
]
},
Expand All @@ -98,7 +97,7 @@
}
},
"devDependencies": {
"@electron/rebuild": "^3.7.2",
"@electron/rebuild": "3.7.2",
"@headlessui/react": "^1.4.2",
"@iconscout/react-unicons": "^1.1.6",
"@internxt/eslint-config-internxt": "^1.0.9",
Expand Down Expand Up @@ -143,8 +142,8 @@
"detect-port": "^1.3.0",
"dotenv": "^10.0.0",
"dotenv-webpack": "^7.0.3",
"electron": "^29.0.0",
"electron-builder": "^23.6.0",
"electron": "29.0.0",
"electron-builder": "23.6.0",
"electron-debug": "^3.2.0",
"electron-fetch": "^1.9.1",
"electron-store": "^8.0.1",
Expand Down Expand Up @@ -206,7 +205,7 @@
"@internxt/sdk": "1.11.17",
"async": "^3.2.4",
"axios": "^1.1.3",
"better-sqlite3": "^11.10.0",
"better-sqlite3": "11.10.0",
"bottleneck": "^2.19.5",
"check-disk-space": "^3.4.0",
"diod": "^2.0.0",
Expand All @@ -225,4 +224,4 @@
"engines": {
"node": ">=20.0.0 <21.0.0"
}
}
}
5 changes: 4 additions & 1 deletion packages/fuse-daemon/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
.PHONY: build test lint

GOFLAGS ?= -mod=readonly -trimpath -buildvcs=false
LDFLAGS ?= -s -w

build:
go build -ldflags="-s -w" -o ../../dist/fuse-daemon ./cmd/daemon
go build $(GOFLAGS) -ldflags="$(LDFLAGS)" -o ../../dist/fuse-daemon ./cmd/daemon
Comment on lines +3 to +7
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary?

Copy link
Copy Markdown
Author

@egalvis27 egalvis27 May 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • mod=readonly: Ensures Go modules are not modified during build, enforcing strict reproducibility and preventing accidental changes to go.mod/go.sum in CI/CD.
  • trimpath: Removes local file system paths from the compiled binary, making builds more deterministic and preventing leakage of developer machine paths.
  • buildvcs=false: Disables embedding VCS (git) metadata in the binary, so builds are not affected by the local repository state or commit hash, further improving reproducibility.
  • s -w (LDFLAGS): Strips symbol table and debug information from the binary, reducing its size and minimizing the amount of non-deterministic metadata.


test:
go test ./...
Expand Down
Loading
Loading