Skip to content

Commit

Permalink
Pollers can update their own secrets
Browse files Browse the repository at this point in the history
  • Loading branch information
bryophyta committed Jan 10, 2025
1 parent 684492e commit 07c0487
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 39 deletions.
23 changes: 19 additions & 4 deletions poller-lambdas/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { GetSecretValueCommand } from '@aws-sdk/client-secrets-manager';
import {
GetSecretValueCommand,
PutSecretValueCommand,
} from '@aws-sdk/client-secrets-manager';
import type { SendMessageCommandInput } from '@aws-sdk/client-sqs';
import { SendMessageCommand } from '@aws-sdk/client-sqs';
import type { PollerId } from '../../shared/pollers';
Expand All @@ -14,12 +17,13 @@ const pollerWrapper =
(pollerFunction: PollFunction) =>
async ({ Records }: HandlerInputSqsPayload) => {
const startTimeEpochMillis = Date.now();
const secretName = getEnvironmentVariableOrCrash(
POLLER_LAMBDA_ENV_VAR_KEYS.SECRET_NAME,
);
const secret = await secretsManager
.send(
new GetSecretValueCommand({
SecretId: getEnvironmentVariableOrCrash(
POLLER_LAMBDA_ENV_VAR_KEYS.SECRET_NAME,
),
SecretId: secretName,
}),
)
.then((_) => _.SecretString);
Expand Down Expand Up @@ -90,6 +94,17 @@ const pollerWrapper =
MessageBody: output.valueForNextPoll,
});
}

if (output.newSecretValue) {
// set new value in secrets manager
console.log(`Updating secret value for ${secretName}`);
await secretsManager.send(
new PutSecretValueCommand({
SecretId: secretName,
SecretString: output.newSecretValue,
}),
);
}
})
.catch((error) => {
console.error('FAILED', error);
Expand Down
11 changes: 7 additions & 4 deletions poller-lambdas/src/pollers/reuters/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ const AuthSchema = z.object({
token_type: z.string(),
});

type AuthData = z.infer<typeof AuthSchema>;

const scopes =
'https://api.thomsonreuters.com/auth/reutersconnect.contentapi.read https://api.thomsonreuters.com/auth/reutersconnect.contentapi.write';
const authUrl = 'https://auth.thomsonreuters.com/oauth/token';
Expand All @@ -17,7 +15,7 @@ const audience = '7a14b6a2-73b8-4ab2-a610-80fb9f40f769';
export async function auth(
clientId: string,
clientSecret: string,
): Promise<AuthData> {
): Promise<string> {
const req = new Request(authUrl, {
method: 'POST',
headers: {
Expand All @@ -26,9 +24,14 @@ export async function auth(
body: `grant_type=${grantType}&client_id=${clientId}&client_secret=${clientSecret}&audience=${audience}&scope=${encodeURIComponent(scopes)}`,
});
try {
console.log('Requesting new auth token from Reuters');
const response = await fetch(req);
const data = (await response.json()) as unknown;
return AuthSchema.parse(data);
const { access_token, expires_in } = AuthSchema.parse(data);
console.log(
`Received new auth token from Reuters, expires in ${expires_in} seconds`,
);
return access_token;
} catch (error) {
console.error(error);
throw new Error('Failed to get auth token from Reuters');
Expand Down
70 changes: 39 additions & 31 deletions poller-lambdas/src/pollers/reuters/reutersPoller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ function itemResponseToIngestionLambdaInput(
const SecretValueSchema = z.object({
CLIENT_ID: z.string(),
CLIENT_SECRET: z.string(),
ACCESS_TOKEN: z.string().optional(),
});

export const reutersPoller = (async (
Expand All @@ -188,49 +189,56 @@ export const reutersPoller = (async (
if (!parsedSecret.success) {
throw new Error('Failed to parse secret value for Reuters poller');
}
const { CLIENT_ID, CLIENT_SECRET } = parsedSecret.data;
const { access_token } = await auth(
CLIENT_ID,
CLIENT_SECRET,
); /** @todo: the tokens are quite long-lived so we should check that there aren't any problems requesting one on each invocation. */
const { CLIENT_ID, CLIENT_SECRET, ACCESS_TOKEN } = parsedSecret.data;

const searchResponse = await fetch(
'https://api.reutersconnect.com/content/graphql',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${access_token}`,
},
body: JSON.stringify({
query: textItemsSearchQuery,
}),
},
);
let accessToken = ACCESS_TOKEN ?? (await auth(CLIENT_ID, CLIENT_SECRET));

const searchData = SearchDataSchema.parse(await searchResponse.json());

const itemsToFetch = searchData.data.search.items
.map((item) => item.versionedGuid)
.filter((guid): guid is string => guid !== undefined);

const itemResponses = await Promise.all(
itemsToFetch.map(async (itemId) => {
const itemResponse = await fetch(
async function fetchWithReauth(query: string) {
let searchResponse = await fetch(
'https://api.reutersconnect.com/content/graphql',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
body: JSON.stringify({
query: query,
}),
},
);
if (searchResponse.status === 401 || searchResponse.status === 419) {
const newAccessToken = await auth(CLIENT_ID, CLIENT_SECRET);
accessToken = newAccessToken;
searchResponse = await fetch(
'https://api.reutersconnect.com/content/graphql',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${access_token}`,
Authorization: `Bearer ${accessToken}`,
},
body: JSON.stringify({
query: itemQuery(itemId),
query: textItemsSearchQuery,
}),
},
);
return itemResponseSchema.parse(await itemResponse.json());
}),
}
return await searchResponse.json();

Check failure on line 227 in poller-lambdas/src/pollers/reuters/reutersPoller.ts

View workflow job for this annotation

GitHub Actions / Build and upload to riffraff

Unsafe return of an `any` typed value
}

const searchData = SearchDataSchema.parse(
await fetchWithReauth(textItemsSearchQuery),
);

const itemsToFetch = searchData.data.search.items
.map((item) => item.versionedGuid)
.filter((guid): guid is string => guid !== undefined);

const itemResponses = await Promise.all(
itemsToFetch.map(async (itemId) =>
itemResponseSchema.parse(await fetchWithReauth(itemQuery(itemId))),
),
);

return {
Expand Down
1 change: 1 addition & 0 deletions poller-lambdas/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export type PollerInput = string;
export interface CorePollerOutput {
payloadForIngestionLambda: IngestorPayload[] | IngestorPayload;
valueForNextPoll: PollerInput;
newSecretValue?: SecretValue;
}
export type LongPollOutput = CorePollerOutput;

Expand Down

0 comments on commit 07c0487

Please sign in to comment.