Skip to content
Merged
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
43 changes: 42 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ Add the following ACL changes:

TBD: Vultr/Digital Ocean/AWS

### Step 3: Set environment variables
### Step 3: Configuration

You can configure tailportal using either environment variables or a JSON configuration file.

#### Option A: Environment Variables

Create a `.env` file or set these environment variables:

Expand All @@ -71,6 +75,43 @@ PULUMI_CONFIG_PASSPHRASE=your_pulumi_passphrase
TS_AUTH_KEY=your_tailscale_auth_key
```

#### Option B: JSON Configuration

Create a configuration file in one of the following locations (in order of preference):

1. `$XDG_CONFIG_HOME/tailportal/config.json` (if XDG_CONFIG_HOME is set)
2. `~/.config/tailportal/config.json` (recommended)
3. `~/.tailportal.json` (legacy location)

Example configuration:

```json
{
"tsAuthKey": "your_tailscale_auth_key",
"pulumiPassphrase": "your_pulumi_passphrase",
"vultrApiKey": "your_vultr_api_key",
"googleProject": "your_google_project",
"googleCredentials": "your_google_credentials"
}
```

You can also use environment variable interpolation in the JSON config:

```json
{
"tsAuthKey": "$TS_AUTH_KEY",
"pulumiPassphrase": "$PULUMI_CONFIG_PASSPHRASE",
"vultrApiKey": "$VULTR_API_KEY"
}
```

**Configuration File Locations** (searched in order):
- `$XDG_CONFIG_HOME/tailportal/config.json` (if XDG_CONFIG_HOME is set)
- `~/.config/tailportal/config.json` (XDG Base Directory fallback)
- `~/.tailportal.json` (legacy location for backward compatibility)

**Note:** JSON configuration takes precedence over environment variables. If both are present, JSON values will be used.

### Step 4: Run

Once installed globally and environment variables are set:
Expand Down
60 changes: 6 additions & 54 deletions packages/tailportal/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,10 @@ import { regions } from "vultr-types";
import { type CloudProvider, cloudProviders } from "./src/types";
import { program } from "commander";
import { z } from "zod";
import { loadConfig } from "./src/config";

dotenv.config();

function validateEnvironment() {
const tsAuthKey = process.env.TS_AUTH_KEY;
if (!tsAuthKey) {
throw new Error("TS_AUTH_KEY environment variable is required");
}

const pulumiPassphrase = process.env.PULUMI_CONFIG_PASSPHRASE;
if (!pulumiPassphrase) {
throw new Error("PULUMI_CONFIG_PASSPHRASE environment variable is required");
}

return { tsAuthKey, pulumiPassphrase };
}

const stackName = "dev";
const projectName = "tailportal";

Expand All @@ -36,14 +23,7 @@ program
.command("create <provider> [region]")
.description("Create a new instance")
.action(async (provider: string, region: string | undefined) => {
const { tsAuthKey, pulumiPassphrase } = validateEnvironment();
const config = {
tsAuthKey,
pulumiPassphrase,
vultrApiKey: process.env.VULTR_API_KEY,
googleProject: process.env.GOOGLE_PROJECT,
googleCredentials: process.env.GOOGLE_CREDENTIALS,
};
const config = loadConfig();

const createSchema = z.object({
provider: z.string(),
Expand Down Expand Up @@ -86,14 +66,7 @@ program
.command("destroy")
.description("Destroy the stack")
.action(async () => {
const { tsAuthKey, pulumiPassphrase } = validateEnvironment();
const config = {
tsAuthKey,
pulumiPassphrase,
vultrApiKey: process.env.VULTR_API_KEY,
googleProject: process.env.GOOGLE_PROJECT,
googleCredentials: process.env.GOOGLE_CREDENTIALS,
};
const config = loadConfig();


const instanceManager = new InstanceManager(config, stackName, projectName);
Expand All @@ -106,14 +79,7 @@ program
.command("list")
.description("List current instances")
.action(async () => {
const { tsAuthKey, pulumiPassphrase } = validateEnvironment();
const config = {
tsAuthKey,
pulumiPassphrase,
vultrApiKey: process.env.VULTR_API_KEY,
googleProject: process.env.GOOGLE_PROJECT,
googleCredentials: process.env.GOOGLE_CREDENTIALS,
};
const config = loadConfig();


const instanceManager = new InstanceManager(config, stackName, projectName);
Expand All @@ -125,14 +91,7 @@ program
.command("remove <name>")
.description("Remove an instance by name")
.action(async (name: string) => {
const { tsAuthKey, pulumiPassphrase } = validateEnvironment();
const config = {
tsAuthKey,
pulumiPassphrase,
vultrApiKey: process.env.VULTR_API_KEY,
googleProject: process.env.GOOGLE_PROJECT,
googleCredentials: process.env.GOOGLE_CREDENTIALS,
};
const config = loadConfig();


const instanceManager = new InstanceManager(config, stackName, projectName);
Expand All @@ -155,14 +114,7 @@ program
.command("sync")
.description("Synchronize the stack with the current state")
.action(async () => {
const { tsAuthKey, pulumiPassphrase } = validateEnvironment();
const config = {
tsAuthKey,
pulumiPassphrase,
vultrApiKey: process.env.VULTR_API_KEY,
googleProject: process.env.GOOGLE_PROJECT,
googleCredentials: process.env.GOOGLE_CREDENTIALS,
};
const config = loadConfig();


const instanceManager = new InstanceManager(config, stackName, projectName);
Expand Down
4 changes: 3 additions & 1 deletion packages/tailportal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@
"scripts": {
"build": "esbuild index.ts --bundle --platform=node --target=node18 --format=cjs --outfile=dist/index.js --external:@pulumi/pulumi --external:@pulumi/gcp --external:@ediri/vultr --external:commander --external:dotenv --external:tsx --external:zod",
"prepublishOnly": "npm run build",
"test": "../../e2e/test-installation.sh",
"test": "npm run test:unit && ../../e2e/test-installation.sh",
"test:unit": "npx tsx --test src/config.test.ts",
"test:e2e": "../../e2e/test-installation.sh",
"start": "tsx index.ts",
"fmt": "npx prettier --write ."
},
Expand Down
Loading