Skip to content
Merged
Prev Previous commit
Next Next commit
Add predicates for Auth types
  • Loading branch information
mbg committed Mar 10, 2026
commit 37eb89b1730e3e5d370e53d8791a44289eb0fa2f
7 changes: 6 additions & 1 deletion src/start-proxy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,12 @@ test.serial(
t.is(results.length, 1);
t.is(results[0].type, "git_server");
t.is(results[0].host, "https://github.com/");
t.assert(results[0].password?.startsWith("ghp_"));

if (startProxyExports.isUsernamePassword(results[0])) {
t.assert(results[0].password?.startsWith("ghp_"));
} else {
t.fail("Expected a `UsernamePassword`-based credential.");
}

// A warning should have been logged.
checkExpectedLogMessages(t, loggedMessages, [
Expand Down
62 changes: 61 additions & 1 deletion src/start-proxy/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { isDefined } from "../util";

/**
* After parsing configurations from JSON, we don't know whether all the keys we expect are
* present or not. This type is used to represent such values, which we expect to be
Expand All @@ -11,6 +13,11 @@ export type Username = {
username?: string;
};

/** Decides whether `config` has a username. */
export function hasUsername(config: Partial<AuthConfig>): config is Username {
return "username" in config;
}

/**
* Fields expected for authentication based on a username and password.
* Both username and password are optional.
Expand All @@ -20,6 +27,13 @@ export type UsernamePassword = {
password?: string;
} & Username;

/** Decides whether `config` is based on a username and password. */
export function isUsernamePassword(
config: AuthConfig,
): config is UsernamePassword {
return hasUsername(config) && "password" in config;
}

/**
* Fields expected for token-based authentication.
* Both username and token are optional.
Expand All @@ -29,9 +43,26 @@ export type Token = {
token?: string;
} & Username;

/** Decides whether `config` is token-based. */
export function isToken(config: Partial<AuthConfig>): config is Token {
return "token" in config;
}

/** Configuration for Azure OIDC. */
export type AzureConfig = { tenant_id: string; client_id: string };

/** Decides whether `config` is an Azure OIDC configuration. */
export function isAzureConfig(
config: Partial<AuthConfig>,
): config is AzureConfig {
return (
"tenant_id" in config &&
"client_id" in config &&
isDefined(config.tenant_id) &&
isDefined(config.client_id)
Comment thread
mbg marked this conversation as resolved.
Outdated
);
}

/** Configuration for AWS OIDC. */
export type AWSConfig = {
aws_region: string;
Expand All @@ -42,18 +73,47 @@ export type AWSConfig = {
audience?: string;
};

/** Decides whether `config` is an AWS OIDC configuration. */
export function isAWSConfig(config: Partial<AuthConfig>): config is AWSConfig {
// All of these properties are required.
const requiredProperties = [
"aws_region",
"account_id",
"role_name",
"domain",
"domain_owner",
];

for (const property of requiredProperties) {
if (!(property in config) || !isDefined(config[property])) {
return false;
}
}
return true;
}

/** Configuration for JFrog OIDC. */
export type JFrogConfig = {
jfrog_oidc_provider_name: string;
audience?: string;
identity_mapping_name?: string;
};

/** Decides whether `config` is a JFrog OIDC configuration. */
export function isJFrogConfig(
config: Partial<AuthConfig>,
): config is JFrogConfig {
return (
"jfrog_oidc_provider_name" in config &&
isDefined(config.jfrog_oidc_provider_name)
);
}

/** Represents all supported OIDC configurations. */
export type OIDC = AzureConfig | AWSConfig | JFrogConfig;

/** All authentication-related fields. */
export type AuthConfig = UsernamePassword & Token & OIDC;
export type AuthConfig = UsernamePassword | Token | OIDC;

/**
* A package registry configuration includes identifying information as well as
Expand Down