mirror of
https://github.com/github/codeql-action
synced 2026-05-23 20:00:54 +03:00
Type result of parsing JSON as unknown until narrowed
This commit is contained in:
Generated
+51
-19
@@ -47749,12 +47749,12 @@ var require_concat_map = __commonJS({
|
||||
var res = [];
|
||||
for (var i = 0; i < xs.length; i++) {
|
||||
var x = fn(xs[i], i);
|
||||
if (isArray(x)) res.push.apply(res, x);
|
||||
if (isArray2(x)) res.push.apply(res, x);
|
||||
else res.push(x);
|
||||
}
|
||||
return res;
|
||||
};
|
||||
var isArray = Array.isArray || function(xs) {
|
||||
var isArray2 = Array.isArray || function(xs) {
|
||||
return Object.prototype.toString.call(xs) === "[object Array]";
|
||||
};
|
||||
}
|
||||
@@ -52097,8 +52097,8 @@ var require_object = __commonJS({
|
||||
"node_modules/@typespec/ts-http-runtime/dist/commonjs/util/object.js"(exports2) {
|
||||
"use strict";
|
||||
Object.defineProperty(exports2, "__esModule", { value: true });
|
||||
exports2.isObject = isObject2;
|
||||
function isObject2(input) {
|
||||
exports2.isObject = isObject3;
|
||||
function isObject3(input) {
|
||||
return typeof input === "object" && input !== null && !Array.isArray(input) && !(input instanceof RegExp) && !(input instanceof Date);
|
||||
}
|
||||
}
|
||||
@@ -56584,7 +56584,7 @@ var require_commonjs4 = __commonJS({
|
||||
exports2.computeSha256Hmac = computeSha256Hmac;
|
||||
exports2.getRandomIntegerInclusive = getRandomIntegerInclusive;
|
||||
exports2.isError = isError;
|
||||
exports2.isObject = isObject2;
|
||||
exports2.isObject = isObject3;
|
||||
exports2.randomUUID = randomUUID;
|
||||
exports2.uint8ArrayToString = uint8ArrayToString;
|
||||
exports2.stringToUint8Array = stringToUint8Array;
|
||||
@@ -56631,7 +56631,7 @@ var require_commonjs4 = __commonJS({
|
||||
function isError(e) {
|
||||
return tspRuntime.isError(e);
|
||||
}
|
||||
function isObject2(input) {
|
||||
function isObject3(input) {
|
||||
return tspRuntime.isObject(input);
|
||||
}
|
||||
function randomUUID() {
|
||||
@@ -121350,6 +121350,23 @@ function isAuthToken(value, patterns = GITHUB_TOKEN_PATTERNS) {
|
||||
return void 0;
|
||||
}
|
||||
|
||||
// src/json/index.ts
|
||||
function parseString(data) {
|
||||
return JSON.parse(data);
|
||||
}
|
||||
function isObject2(value) {
|
||||
return typeof value === "object";
|
||||
}
|
||||
function isArray(value) {
|
||||
return Array.isArray(value);
|
||||
}
|
||||
function isString(value) {
|
||||
return typeof value === "string";
|
||||
}
|
||||
function isStringOrUndefined(value) {
|
||||
return value === void 0 || isString(value);
|
||||
}
|
||||
|
||||
// src/languages.ts
|
||||
var KnownLanguage = /* @__PURE__ */ ((KnownLanguage2) => {
|
||||
KnownLanguage2["actions"] = "actions";
|
||||
@@ -121373,10 +121390,10 @@ function isUsernamePassword(config) {
|
||||
return hasUsername(config) && "password" in config;
|
||||
}
|
||||
function isToken(config) {
|
||||
return "token" in config;
|
||||
return "token" in config && isStringOrUndefined(config.token);
|
||||
}
|
||||
function isAzureConfig(config) {
|
||||
return "tenant_id" in config && "client_id" in config && isDefined2(config.tenant_id) && isDefined2(config.client_id);
|
||||
return "tenant_id" in config && "client_id" in config && isDefined2(config.tenant_id) && isDefined2(config.client_id) && isString(config.tenant_id) && isString(config.client_id);
|
||||
}
|
||||
function isAWSConfig(config) {
|
||||
const requiredProperties = [
|
||||
@@ -121387,14 +121404,23 @@ function isAWSConfig(config) {
|
||||
"domain_owner"
|
||||
];
|
||||
for (const property of requiredProperties) {
|
||||
if (!(property in config) || !isDefined2(config[property])) {
|
||||
if (!(property in config) || !isDefined2(config[property]) || !isString(config[property])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ("audience" in config && !isStringOrUndefined(config.audience)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function isJFrogConfig(config) {
|
||||
return "jfrog_oidc_provider_name" in config && isDefined2(config.jfrog_oidc_provider_name);
|
||||
if ("audience" in config && !isStringOrUndefined(config.audience)) {
|
||||
return false;
|
||||
}
|
||||
if ("identity_mapping_name" in config && !isStringOrUndefined(config.identity_mapping_name)) {
|
||||
return false;
|
||||
}
|
||||
return "jfrog_oidc_provider_name" in config && isDefined2(config.jfrog_oidc_provider_name) && isString(config.jfrog_oidc_provider_name);
|
||||
}
|
||||
function credentialToStr(credential) {
|
||||
let result = `Type: ${credential.type};`;
|
||||
@@ -121829,12 +121855,12 @@ var NEW_LANGUAGE_TO_REGISTRY_TYPE = {
|
||||
go: ["goproxy_server", "git_source"]
|
||||
};
|
||||
function getRegistryAddress(registry) {
|
||||
if (isDefined2(registry.url)) {
|
||||
if (isDefined2(registry.url) && isString(registry.url) && isStringOrUndefined(registry.host)) {
|
||||
return {
|
||||
url: registry.url,
|
||||
host: registry.host
|
||||
};
|
||||
} else if (isDefined2(registry.host)) {
|
||||
} else if (isDefined2(registry.host) && isString(registry.host)) {
|
||||
return {
|
||||
url: void 0,
|
||||
host: registry.host
|
||||
@@ -121872,12 +121898,18 @@ function getAuthConfig(config) {
|
||||
}
|
||||
return { username: config.username, token: config.token };
|
||||
} else {
|
||||
if ("password" in config && isDefined2(config.password)) {
|
||||
let username = void 0;
|
||||
let password = void 0;
|
||||
if ("password" in config && isString(config.password)) {
|
||||
core10.setSecret(config.password);
|
||||
password = config.password;
|
||||
}
|
||||
if ("username" in config && isString(config.username)) {
|
||||
username = config.username;
|
||||
}
|
||||
return {
|
||||
username: "username" in config ? config.username : void 0,
|
||||
password: "password" in config ? config.password : void 0
|
||||
username,
|
||||
password
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -121897,22 +121929,22 @@ function getCredentials(logger, registrySecrets, registriesCredentials, language
|
||||
}
|
||||
let parsed;
|
||||
try {
|
||||
parsed = JSON.parse(credentialsStr);
|
||||
parsed = parseString(credentialsStr);
|
||||
} catch {
|
||||
logger.error("Failed to parse the credentials data.");
|
||||
throw new ConfigurationError("Invalid credentials format.");
|
||||
}
|
||||
if (!Array.isArray(parsed)) {
|
||||
if (!isArray(parsed)) {
|
||||
throw new ConfigurationError(
|
||||
"Expected credentials data to be an array of configurations, but it is not."
|
||||
);
|
||||
}
|
||||
const out = [];
|
||||
for (const e of parsed) {
|
||||
if (e === null || typeof e !== "object") {
|
||||
if (e === null || !isObject2(e)) {
|
||||
throw new ConfigurationError("Invalid credentials - must be an object");
|
||||
}
|
||||
if (!isDefined2(e.type)) {
|
||||
if (!isDefined2(e.type) || !isString(e.type)) {
|
||||
throw new ConfigurationError("Invalid credentials - must have a type");
|
||||
}
|
||||
const authConfig = getAuthConfig(e);
|
||||
|
||||
+46
-18
@@ -17,11 +17,11 @@ import {
|
||||
Feature,
|
||||
FeatureEnablement,
|
||||
} from "./feature-flags";
|
||||
import * as json from "./json";
|
||||
import { KnownLanguage } from "./languages";
|
||||
import { Logger } from "./logging";
|
||||
import {
|
||||
Address,
|
||||
RawCredential,
|
||||
Registry,
|
||||
Credential,
|
||||
AuthConfig,
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
JFrogConfig,
|
||||
isUsernamePassword,
|
||||
hasUsername,
|
||||
RawCredential,
|
||||
} from "./start-proxy/types";
|
||||
import {
|
||||
ActionName,
|
||||
@@ -267,13 +268,19 @@ const NEW_LANGUAGE_TO_REGISTRY_TYPE: Required<RegistryMapping> = {
|
||||
*
|
||||
* @throws A `ConfigurationError` if the `Registry` value contains neither a `url` or `host` field.
|
||||
*/
|
||||
function getRegistryAddress(registry: Partial<Registry>): Address {
|
||||
if (isDefined(registry.url)) {
|
||||
function getRegistryAddress(
|
||||
registry: json.UnvalidatedObject<Registry>,
|
||||
): Address {
|
||||
if (
|
||||
isDefined(registry.url) &&
|
||||
json.isString(registry.url) &&
|
||||
json.isStringOrUndefined(registry.host)
|
||||
) {
|
||||
return {
|
||||
url: registry.url,
|
||||
host: registry.host,
|
||||
};
|
||||
} else if (isDefined(registry.host)) {
|
||||
} else if (isDefined(registry.host) && json.isString(registry.host)) {
|
||||
return {
|
||||
url: undefined,
|
||||
host: registry.host,
|
||||
@@ -287,7 +294,9 @@ function getRegistryAddress(registry: Partial<Registry>): Address {
|
||||
}
|
||||
|
||||
/** Extracts an `AuthConfig` value from `config`. */
|
||||
export function getAuthConfig(config: Partial<AuthConfig>): AuthConfig {
|
||||
export function getAuthConfig(
|
||||
config: json.UnvalidatedObject<AuthConfig>,
|
||||
): AuthConfig {
|
||||
// Start by checking for the OIDC configurations, since they have required properties
|
||||
// which we can use to identify them.
|
||||
if (isAzureConfig(config)) {
|
||||
@@ -311,25 +320,44 @@ export function getAuthConfig(config: Partial<AuthConfig>): AuthConfig {
|
||||
audience: config.audience,
|
||||
} satisfies JFrogConfig;
|
||||
} else if (isToken(config)) {
|
||||
// For token-based authentication, both the token and username are optional.
|
||||
// If the token is absent, then it doesn't matter if we end up treating it
|
||||
// as a `UsernamePassword` object internally.
|
||||
// There are three scenarios for non-OIDC authentication based on the registry type:
|
||||
//
|
||||
// 1. `username`+`token`
|
||||
// 2. A `token` that combines the username and actual token, seperated by ':'.
|
||||
// 3. `username`+`password`
|
||||
//
|
||||
// In all three cases, all fields are optional. If the `token` field is present,
|
||||
// we accept the configuration as a `Token` typed configuration, with the `token`
|
||||
// value and an optional `username`. Otherwise, we accept the configuration
|
||||
// typed as `UsernamePassword` (in the `else` clause below) with optional
|
||||
// username and password. I.e. a private registry type that uses 1. or 2.,
|
||||
// but has no `token` configured, will get accepted as `UsernamePassword` here.
|
||||
|
||||
// Mask token to reduce chance of accidental leakage in logs, if we have one.
|
||||
if (isDefined(config.token)) {
|
||||
// Mask token to reduce chance of accidental leakage in logs, if we have one.
|
||||
core.setSecret(config.token);
|
||||
}
|
||||
|
||||
return { username: config.username, token: config.token } satisfies Token;
|
||||
} else {
|
||||
// Mask password to reduce chance of accidental leakage in logs, if we have one.
|
||||
if ("password" in config && isDefined(config.password)) {
|
||||
let username: string | undefined = undefined;
|
||||
let password: string | undefined = undefined;
|
||||
|
||||
// Both "username" and "password" are optional. If we have reached this point, we need
|
||||
// to validate which of them are present and that they have the correct type if so.
|
||||
if ("password" in config && json.isString(config.password)) {
|
||||
// Mask password to reduce chance of accidental leakage in logs, if we have one.
|
||||
core.setSecret(config.password);
|
||||
password = config.password;
|
||||
}
|
||||
if ("username" in config && json.isString(config.username)) {
|
||||
username = config.username;
|
||||
}
|
||||
|
||||
// Return the `UsernamePassword` object. Both username and password may be undefined.
|
||||
return {
|
||||
username: "username" in config ? config.username : undefined,
|
||||
password: "password" in config ? config.password : undefined,
|
||||
username,
|
||||
password,
|
||||
} satisfies UsernamePassword;
|
||||
}
|
||||
}
|
||||
@@ -364,9 +392,9 @@ export function getCredentials(
|
||||
}
|
||||
|
||||
// Parse and validate the credentials
|
||||
let parsed: RawCredential[];
|
||||
let parsed: unknown;
|
||||
try {
|
||||
parsed = JSON.parse(credentialsStr) as RawCredential[];
|
||||
parsed = json.parseString(credentialsStr);
|
||||
} catch {
|
||||
// Don't log the error since it might contain sensitive information.
|
||||
logger.error("Failed to parse the credentials data.");
|
||||
@@ -374,7 +402,7 @@ export function getCredentials(
|
||||
}
|
||||
|
||||
// Check that the parsed data is indeed an array.
|
||||
if (!Array.isArray(parsed)) {
|
||||
if (!json.isArray(parsed)) {
|
||||
throw new ConfigurationError(
|
||||
"Expected credentials data to be an array of configurations, but it is not.",
|
||||
);
|
||||
@@ -382,12 +410,12 @@ export function getCredentials(
|
||||
|
||||
const out: Credential[] = [];
|
||||
for (const e of parsed) {
|
||||
if (e === null || typeof e !== "object") {
|
||||
if (e === null || !json.isObject<RawCredential>(e)) {
|
||||
throw new ConfigurationError("Invalid credentials - must be an object");
|
||||
}
|
||||
|
||||
// The configuration must have a type.
|
||||
if (!isDefined(e.type)) {
|
||||
if (!isDefined(e.type) || !json.isString(e.type)) {
|
||||
throw new ConfigurationError("Invalid credentials - must have a type");
|
||||
}
|
||||
|
||||
|
||||
+40
-10
@@ -1,3 +1,5 @@
|
||||
import type { UnvalidatedObject } from "../json";
|
||||
import * as json from "../json";
|
||||
import { isDefined } from "../util";
|
||||
|
||||
/**
|
||||
@@ -5,7 +7,7 @@ import { isDefined } from "../util";
|
||||
* present or not. This type is used to represent such values, which we expect to be
|
||||
* `Credential` values, but haven't validated yet.
|
||||
*/
|
||||
export type RawCredential = Partial<Credential>;
|
||||
export type RawCredential = UnvalidatedObject<Credential>;
|
||||
|
||||
/** Usernames may be present for both authentication with tokens or passwords. */
|
||||
export type Username = {
|
||||
@@ -14,7 +16,7 @@ export type Username = {
|
||||
};
|
||||
|
||||
/** Decides whether `config` has a username. */
|
||||
export function hasUsername(config: Partial<AuthConfig>): config is Username {
|
||||
export function hasUsername(config: AuthConfig): config is Username {
|
||||
return "username" in config;
|
||||
}
|
||||
|
||||
@@ -44,8 +46,10 @@ export type Token = {
|
||||
} & Username;
|
||||
|
||||
/** Decides whether `config` is token-based. */
|
||||
export function isToken(config: Partial<AuthConfig>): config is Token {
|
||||
return "token" in config;
|
||||
export function isToken(
|
||||
config: UnvalidatedObject<AuthConfig>,
|
||||
): config is Token {
|
||||
return "token" in config && json.isStringOrUndefined(config.token);
|
||||
}
|
||||
|
||||
/** Configuration for Azure OIDC. */
|
||||
@@ -53,13 +57,15 @@ export type AzureConfig = { tenant_id: string; client_id: string };
|
||||
|
||||
/** Decides whether `config` is an Azure OIDC configuration. */
|
||||
export function isAzureConfig(
|
||||
config: Partial<AuthConfig>,
|
||||
config: UnvalidatedObject<AuthConfig>,
|
||||
): config is AzureConfig {
|
||||
return (
|
||||
"tenant_id" in config &&
|
||||
"client_id" in config &&
|
||||
isDefined(config.tenant_id) &&
|
||||
isDefined(config.client_id)
|
||||
isDefined(config.client_id) &&
|
||||
json.isString(config.tenant_id) &&
|
||||
json.isString(config.client_id)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -74,7 +80,9 @@ export type AWSConfig = {
|
||||
};
|
||||
|
||||
/** Decides whether `config` is an AWS OIDC configuration. */
|
||||
export function isAWSConfig(config: Partial<AuthConfig>): config is AWSConfig {
|
||||
export function isAWSConfig(
|
||||
config: UnvalidatedObject<AuthConfig>,
|
||||
): config is AWSConfig {
|
||||
// All of these properties are required.
|
||||
const requiredProperties = [
|
||||
"aws_region",
|
||||
@@ -85,10 +93,20 @@ export function isAWSConfig(config: Partial<AuthConfig>): config is AWSConfig {
|
||||
];
|
||||
|
||||
for (const property of requiredProperties) {
|
||||
if (!(property in config) || !isDefined(config[property])) {
|
||||
if (
|
||||
!(property in config) ||
|
||||
!isDefined(config[property]) ||
|
||||
!json.isString(config[property])
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The "audience" field is optional, but should be a string if present.
|
||||
if ("audience" in config && !json.isStringOrUndefined(config.audience)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -101,11 +119,23 @@ export type JFrogConfig = {
|
||||
|
||||
/** Decides whether `config` is a JFrog OIDC configuration. */
|
||||
export function isJFrogConfig(
|
||||
config: Partial<AuthConfig>,
|
||||
config: UnvalidatedObject<AuthConfig>,
|
||||
): config is JFrogConfig {
|
||||
// The "audience" and "identity_mapping_name" fields is optional, but should be strings if present.
|
||||
if ("audience" in config && !json.isStringOrUndefined(config.audience)) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
"identity_mapping_name" in config &&
|
||||
!json.isStringOrUndefined(config.identity_mapping_name)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
"jfrog_oidc_provider_name" in config &&
|
||||
isDefined(config.jfrog_oidc_provider_name)
|
||||
isDefined(config.jfrog_oidc_provider_name) &&
|
||||
json.isString(config.jfrog_oidc_provider_name)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user