Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Add External Source (and External Event) Attribute Validation #116

Open
wants to merge 29 commits into
base: develop
Choose a base branch
from

Conversation

pranav-super
Copy link

@pranav-super pranav-super commented Nov 18, 2024

This pull request adds external source/event attribute validation to Aerie.

This means that when an external source is uploaded to AERIE, via endpoints like the CLI or the UI, it is forwarded here, has its formatting checked against a schema, and additionally has the attributes of the source and each of its events checked for validity, before submitting it to the database.

Submission of event/source type schemas for the purpose of later validation is also handled here - the gateway simply checks that they are valid JSON Schema.

A more thorough explanation of the feature can be found in the AERIE PR, here.

} catch (error) {
logger.error((error as Error).message);
res.status(500);
res.send((error as Error).message);
Copy link
Contributor

@Mythicaeda Mythicaeda Nov 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not Aerie Gateway standard. Do not just send a text message back as an error message, you need to send a JSON. See L43 of middleware.ts for an example of the correct way to return an error status. This applies to all places where you're returning error statuses.

async function uploadExternalEventType(req: Request, res: Response) {
logger.info(`POST /uploadExternalEventType: Entering function...`);
const authorizationHeader = req.get('authorization');
logger.info(`POST /uploadExternalEventType: ${authorizationHeader}`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this, you should never be logging user credentials like this.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry - missed this from cleaning up some testing debugs, removed now!

const ajv = new Ajv();

async function uploadExternalEventType(req: Request, res: Response) {
logger.info(`POST /uploadExternalEventType: Entering function...`);
Copy link
Contributor

@Mythicaeda Mythicaeda Nov 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This log is unnecessary, please remove it.

Comment on lines 37 to 43
if (!schemaIsValid) {
throw new Error("Schema was not a valid JSON Schema.");
}
} catch (error) {
logger.error((error as Error).message);
res.status(500);
res.send((error as Error).message);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can ajv.validateSchema throw an Error? If not, why is this a try-catch? If it can, then this comment can be resolved.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch - no it looks like all errors are just directly accessible through ajv.errors. I updated the logger and res.send statements to use ajv.errors instead of relying on a try / catch.

Comment on lines 45 to 56
try {
if (attribute_schema['title'] === undefined || attribute_schema.title !== external_event_type_name) {
throw new Error('Schema title does not match provided external event type name.');
}
} catch (error) {
logger.error(
`POST /uploadExternalEventType: Error occurred during External Event Type ${external_event_type_name} upload`,
);
logger.error((error as Error).message);
res.status(500).send({ message: (error as Error).message });
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this a try-catch instead of an if-return?

return;
}

logger.info(`POST /uploadExternalEventType: Attribute schema was VALID`);
Copy link
Contributor

@Mythicaeda Mythicaeda Nov 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use present tense in logs, unless the log is explicitly referring to a "prior state":

Suggested change
logger.info(`POST /uploadExternalEventType: Attribute schema was VALID`);
logger.info(`POST /uploadExternalEventType: Attribute schema is VALID`);

method: 'POST',
});

type CreateExternalEventTypeResponse = {
Copy link
Contributor

@Mythicaeda Mythicaeda Nov 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Types should be declared in a file in the types directory, not inline. Additionally, this type should not start at the data wrapper object but just be the middle { attribute_schema: object; name: string }

Please use types/plans.ts for a reference of what I mean.

* tags:
* - Hasura
*/
app.post('/uploadExternalEventType', uploadExternalEventType);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This endpoint is currently unauthenticated. Example of an authenticated endpoint from L716 of packages/plan/plan.ts. Please also speak with @duranb regarding the upload.single part.

app.post('/uploadDataset', upload.single('external_dataset'), refreshLimiter, auth, uploadDataset);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Organization question: why are these separate external-event and external-source packages instead of one united package?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started with them separate since they'd been separated at times when doing the UI work in the original pull-request, but I do think it makes sense to condense to one package - I can't think of a name though, maybe just naming it external-source or external-source-events?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the feature bundled up under the name external-events in the UI? If so, that works. Otherwise external-source works.

@dandelany dandelany added the publish Tells GH to publish docker images for this PR label Nov 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
publish Tells GH to publish docker images for this PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants