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
67 changes: 12 additions & 55 deletions packages/cli/src/user/cmd.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import {
Context,
createFetch,
createInstance,
deleteSecret,
getInstance,
getLogsForInstance,
getPortsForInstance,
listInstances,
listReservedNodes,
listSecrets,
removeInstance,
getInstanceScaling,
restartInstance,
scaleInstanceReplicas
saveSecret,
scaleInstanceReplicas,
updateSecret
} from '@osaas/client-core';
import { Command } from 'commander';
import { confirm, instanceOptsToPayload, makeSafeName } from './util';
Expand Down Expand Up @@ -434,21 +437,8 @@ export function cmdSecrets() {
const globalOpts = command.optsWithGlobals();
const environment = globalOpts?.env || 'prod';
const ctx = new Context({ environment });
const personalAccessToken = await ctx.getPersonalAccessToken();
const secrets = await createFetch<
{ serviceId: string; secretName: string }[]
>(
new URL(
'/mysecrets/' + serviceId,
`https://deploy.svc.${ctx.getEnvironment()}.osaas.io`
),
{
headers: {
'x-pat-jwt': `Bearer ${personalAccessToken}`
}
}
);
secrets.forEach((secret) => {
const secretsList = await listSecrets(serviceId, ctx);
secretsList.forEach((secret) => {
console.log(`${secret.secretName}: ***`);
});
} catch (err) {
Expand All @@ -467,19 +457,7 @@ export function cmdSecrets() {
const globalOpts = command.optsWithGlobals();
const environment = globalOpts?.env || 'prod';
const ctx = new Context({ environment });
const personalAccessToken = await ctx.getPersonalAccessToken();
const secretUrl = new URL(
'/mysecrets/' + serviceId,
`https://deploy.svc.${ctx.getEnvironment()}.osaas.io`
);
await createFetch(secretUrl, {
method: 'POST',
headers: {
'x-pat-jwt': `Bearer ${personalAccessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ secretName, secretData: secretValue })
});
await saveSecret(serviceId, secretName, secretValue, ctx);
console.log(`Secret ${secretName} created successfully.`);
} catch (err) {
console.log((err as Error).message);
Expand All @@ -497,24 +475,13 @@ export function cmdSecrets() {
const globalOpts = command.optsWithGlobals();
const environment = globalOpts?.env || 'prod';
const ctx = new Context({ environment });
const personalAccessToken = await ctx.getPersonalAccessToken();
const secretUrl = new URL(
'/mysecrets/' + serviceId + `/${secretName}`,
`https://deploy.svc.${ctx.getEnvironment()}.osaas.io`
);
await createFetch(secretUrl, {
method: 'PUT',
headers: {
'x-pat-jwt': `Bearer ${personalAccessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ secretData: secretValue })
});
await updateSecret(serviceId, secretName, secretValue, ctx);
console.log(`Secret ${secretName} updated successfully.`);
} catch (err) {
console.log((err as Error).message);
}
});

secrets
.command('remove')
.description('Remove a secret for a service')
Expand All @@ -525,22 +492,12 @@ export function cmdSecrets() {
const globalOpts = command.optsWithGlobals();
const environment = globalOpts?.env || 'prod';
const ctx = new Context({ environment });
const personalAccessToken = await ctx.getPersonalAccessToken();
const secretUrl = new URL(
'/mysecrets/' + serviceId + `/${secretName}`,
`https://deploy.svc.${ctx.getEnvironment()}.osaas.io`
);
await createFetch(secretUrl, {
method: 'DELETE',
headers: {
'x-pat-jwt': `Bearer ${personalAccessToken}`,
'Content-Type': 'application/json'
}
});
await deleteSecret(serviceId, secretName, ctx);
console.log(`Secret ${secretName} removed successfully.`);
} catch (err) {
console.log((err as Error).message);
}
});

return secrets;
}
106 changes: 106 additions & 0 deletions packages/core/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -528,3 +528,109 @@ export async function saveSecret(
}
});
}

/**
* List all secrets for a service in Open Source Cloud.
* Returns metadata only — secret values are write-only by design and are never
* returned by the API.
* @memberof module:@osaas/client-core
* @param {string} serviceId - The service identifier
* @param {Context} ctx - Open Source Cloud configuration context
* @returns {Promise<Array<{serviceId: string, secretName: string}>>} - List of secret metadata
*/
export async function listSecrets(
serviceId: string,
ctx: Context
): Promise<{ serviceId: string; secretName: string }[]> {
const secretsUrl = new URL(
`/mysecrets/${serviceId}`,
`https://deploy.svc.${ctx.getEnvironment()}.osaas.io`
);
return await createFetch<{ serviceId: string; secretName: string }[]>(
secretsUrl,
{
method: 'GET',
headers: {
'x-pat-jwt': `Bearer ${ctx.getPersonalAccessToken()}`,
'Content-Type': 'application/json'
}
}
);
}

/**
* Look up a single secret by name for a service in Open Source Cloud.
* Returns metadata only — secret values are write-only by design and are never
* returned by the API. Returns undefined if the secret does not exist.
*
* Note: implemented client-side via listSecrets + .find() because no
* single-secret GET endpoint exists on the backend.
* @memberof module:@osaas/client-core
* @param {string} serviceId - The service identifier
* @param {string} secretName - The secret name to look up
* @param {Context} ctx - Open Source Cloud configuration context
* @returns {Promise<{serviceId: string, secretName: string} | undefined>} - Secret metadata or undefined
*/
export async function getSecret(
serviceId: string,
secretName: string,
ctx: Context
): Promise<{ serviceId: string; secretName: string } | undefined> {
const secrets = await listSecrets(serviceId, ctx);
return secrets.find((s) => s.secretName === secretName);
}

/**
* Update (upsert) a secret for a service in Open Source Cloud via PUT.
* Use saveSecret for initial creation (POST). updateSecret uses PUT and
* will overwrite an existing secret of the same name.
* @memberof module:@osaas/client-core
* @param {string} serviceId - The service identifier
* @param {string} secretName - The secret name
* @param {string} value - The secret value
* @param {Context} ctx - Open Source Cloud configuration context
*/
export async function updateSecret(
serviceId: string,
secretName: string,
value: string,
ctx: Context
): Promise<void> {
const secretUrl = new URL(
`/mysecrets/${serviceId}/${secretName}`,
`https://deploy.svc.${ctx.getEnvironment()}.osaas.io`
);
await createFetch(secretUrl, {
method: 'PUT',
body: JSON.stringify({ secretData: value }),
headers: {
'x-pat-jwt': `Bearer ${ctx.getPersonalAccessToken()}`,
'Content-Type': 'application/json'
}
});
}

/**
* Delete a secret for a service in Open Source Cloud.
* @memberof module:@osaas/client-core
* @param {string} serviceId - The service identifier
* @param {string} secretName - The secret name to delete
* @param {Context} ctx - Open Source Cloud configuration context
*/
export async function deleteSecret(
serviceId: string,
secretName: string,
ctx: Context
): Promise<void> {
const secretUrl = new URL(
`/mysecrets/${serviceId}/${secretName}`,
`https://deploy.svc.${ctx.getEnvironment()}.osaas.io`
);
await createFetch(secretUrl, {
method: 'DELETE',
headers: {
'x-pat-jwt': `Bearer ${ctx.getPersonalAccessToken()}`,
'Content-Type': 'application/json'
}
});
}
4 changes: 4 additions & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ export {
isValidInstanceName,
waitForInstanceReady,
saveSecret,
listSecrets,
getSecret,
updateSecret,
deleteSecret,
restartInstance,
updateInstance,
getInstanceScaling,
Expand Down
Loading