Skip to content

Conversation

@omarraf
Copy link
Contributor

@omarraf omarraf commented Aug 19, 2025

Description

This PR implements a comprehensive parameter validation testing framework across all routes in src/server/routes as part of a major security initiative. The goal is to address these limitations via systematic testing using OED's standard Chai/Mocha frameworks.

This work builds upon #1512, which established the foundational methodology for the units.js route.

Fixes #1497

Type of change

  • Note merging this changes the database configuration.
  • This change requires a documentation update

Checklist

  • I have followed the OED pull request ideas
  • I have removed text in ( ) from the issue request
  • You acknowledge that every person contributing to this work has signed the OED Contributing License Agreement and each author is listed in the Description section.

Limitations

@omarraf
Copy link
Contributor Author

omarraf commented Aug 19, 2025

Hi @huss, I created this draft PR to get some feedback on the approach before continuing further.

Temporary accommodations made:

  • Some tests are commented out due to failing
  • A few test expectations are broadened to handle auth-first middleware flows
  • Some security limits are conservative estimates vs. actual database constraints

Few questions I had:

  1. Overall approach - does this testing methodology look good?
  2. Security limits - are the hardcoded values reasonable? (1000 char strings, etc.)
  3. Any other immediate concerns?

I just wanted to make sure I'm on the right track before continuing, thanks!

Copy link
Member

@huss huss left a comment

Choose a reason for hiding this comment

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

Thanks to @omarraf for another contribution. First, I would like to verify you are the only one who worked on this. I only see commits from you so just double checking. Second, I think the work is good. I read through some of the files to see how it is generally set up. I've made some comments in these files to give my thoughts. Given this is a draft, I wanted to get my thoughts back sooner rather than later and that some overall changes may be made, I did not do a full review. I hope what I did is useful and please let me know if there are specific files you would like me to look at that I did not. If anything is unclear, you have thoughts or need help then please just let me know.


mocha.describe('Error Handling', () => {
mocha.it('should handle database connection errors gracefully', async () => {
const res = await chai.request(app)
Copy link
Member

Choose a reason for hiding this comment

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

Can you help me understand how a DB error would happen so this actually tests that?

Copy link
Contributor Author

@omarraf omarraf Aug 26, 2025

Choose a reason for hiding this comment

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

The test as written doesn't actually simulate a real database error. It's just making a normal request and expecting it to work. To properly test database error handling, I'd need to either mock the database connection to throw an error or temporarily break the connection somehow. I'll remove this test since it's not actually testing error handling as intended.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe change the description strings so they more accurately reflect the test?

});

mocha.it('should reject invalid meter ID patterns', async () => {
const invalidPatterns = [
Copy link
Member

Choose a reason for hiding this comment

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

Does this apply across several routes so should be centralized? Also, could the map pattern be the base for this pattern with the added ones?

@omarraf
Copy link
Contributor Author

omarraf commented Aug 20, 2025

Hi @huss, I really appreciate you getting back so quickly, I'm going to address all of the comments soon. Just to answer your question real quick:

I would like to verify you are the only one who worked on this

Yes, I ended up working on this alone, as the rest of my team was pulled onto other priorities.

@omarraf
Copy link
Contributor Author

omarraf commented Aug 26, 2025

Thanks again for taking the time to give your feedback @huss. I'll work through improving the PR and let you know if I need any help or need a review.

@omarraf omarraf marked this pull request as ready for review October 27, 2025 23:47
@omarraf
Copy link
Contributor Author

omarraf commented Oct 27, 2025

Hi @huss, I've addressed the comments you provided, let me know if I'm missing anything or need me to clarify.

Changes:

  • Consolidated route schemas to use shared validation constants
  • Updated parameter tests to reuse the helper utilities, handle rate-limited responses
  • Temporarily skipped compareReadings DoS checks (TODO added)

Some web/integration tests are failing in CI, which I didn't address in this PR, didn't do enough digging to figure out why

@omarraf omarraf requested a review from huss October 27, 2025 23:59
@huss
Copy link
Member

huss commented Nov 18, 2025

First, I want to apologize to @omarraf for the long delay in getting to this review. I made a mistake in my task tracking system and lost track of this PR. I'm very sorry this happened.

Second, there are 27 failing tests where most are for Obvius. I think many (all?) are due to changes in route checking. Would it be okay if I try to address them and push out changes?

@omarraf
Copy link
Contributor Author

omarraf commented Nov 18, 2025

No problem at all @huss. Feel free to make any changes

huss added 2 commits November 18, 2025 15:07
- Make them alphabetical in declaration.
- Rename string so it comes first so all go together.
- Add more HTTP_CODE const responses and use in some places.
- Some formatting.
- Use limits in test so always stay in sync.
- formatting
@huss huss mentioned this pull request Nov 19, 2025
5 tasks
huss added 7 commits November 23, 2025 09:38
Did not change comments.
This does not fix other places such as routes.
Also, possible some lines might be too long now.
The new param checking was stricter so the historical use of email
instead of the newer username was causing issues. This uses
username no matter which is used in the request.
Note other values should be tested but another PR already
deals with that.
@huss
Copy link
Member

huss commented Nov 24, 2025

I have seen periodic failure of tests on GitHub and the latest tests have 13 failures that are slightly different. The last 7 are 429/too many requests and I suspect the first 6 are OED's rate limiting error (the message is truncated so not certain). The first 6 might be because the new tests runs so fast and there are so many that it is hitting the limit for the first time. The last 7 are less clear but I did see that src/server/routes/obvius.js has a new limit on multer but I have not checked that possibility out. Note these tests do not fail locally for me. This is going to have to be tracked down and I'm open to ideas.

Copy link
Member

@huss huss left a comment

Choose a reason for hiding this comment

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

Thanks to @omarraf for the updated code. There are a lot of new tests and I appreciate the work in doing this. Overall, this is working well. I've tried to clear any resolved comments and added some more. I have not checked every test vs the route to verify all is being checked. I think that is a future task either after any changes are done or after this PR. One area with several comments is if tests could be generalized and the basic code reused across tests. For example, notes and maybe many strings are similar across params and routes. I don't know if you want to go into this now and it would be fine if it is done after this PR (not necessarily by you). Another point is that the code from the pending PR that started this process such as src/server/test/util/validationHelpers.js is not showing the git record of their having done the work. Did you change any of it or can it be included via that PR?

Please let me know your thoughts on the big picture items so we can decide how they will be addressed. There are other ones (such as using the HTTP codes throughout the coded as now done with route testing) that I plan to post as issues in the future and not in any comments on this PR.

Finally, I welcome your comments on the commits I made. I changed more than I might normally do because you have put in so much work and my review took so long. I hope this was okay.

expect(res.status).to.equal(400);
});

mocha.it.skip('should validate curr_start parameter', async () => { // TODO: re-enable once compareReadings rejects invalid ISO values without hitting DB
Copy link
Member

Choose a reason for hiding this comment

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

OED prefers comments on the line above the code. Applies in several places.

// Response should not reveal whether user exists or not
expect([400, 401]).to.include(res1.status);
});
});
Copy link
Member

Choose a reason for hiding this comment

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

I'm unclear how this tests rate limiting. Could you help me understand? Also, it raised another questing in my mind if we should rate limit in app.js for login attempts with a lower limit. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah looking back at it I think the comment is a bit misleading, it doesn't actually test rate limiting but just checks that all 10 requests fail with 400/401. I can either update the comment or add assertions for 429. Also I think adding a rate limit for logins is a good idea. We could add a seperate rate limiter instance in app.js just for /api/login with a lower threshold. I'm happy to add it in this PR or in a seperate issue.

// Response should not reveal whether user exists or not
expect([400, 401]).to.include(res1.status);
});
});
Copy link
Member

Choose a reason for hiding this comment

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

There seems a lot of similarities to the user test above. Do you think it would be possible to create a more general test to handle both?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There definitely is overlap, both test username/password validation, malicious inputs, and field length limits. I kept them separate mainly because of different context and test organization. Authenticator tests validate middleware behavior (login endpoint), while user tests validate CRUD operations (/create, /edit, /delete)

That said, we could extract the shared test data (malicious username patterns, SQL injection strings, etc.) into a shared fixture file in src/server/test/util/. I can refactor it that way if need be

const ISO_DURATION_REGEX = /^P(?!$)(\d+Y)?(\d+M)?(\d+D)?(T(\d+H)?(\d+M)?(\d+(\.\d+)?S)?)?$/;

function isValidIsoDateTime(value) {
return typeof value === 'string' && moment.parseZone(value, moment.ISO_8601, true).isValid();
Copy link
Member

Choose a reason for hiding this comment

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

I see the value of checking if it is a string. However, doesn't the param validation do this before this runs?

Copy link
Contributor Author

@omarraf omarraf Dec 21, 2025

Choose a reason for hiding this comment

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

Yeah I think you're right, I just added it to be safe but I can remove

expect([400, 500]).to.include(res.status);
});
});
}); No newline at end of file
Copy link
Member

Choose a reason for hiding this comment

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

I think these endpoints should be used in the .get and .describe as possible.

const currEndRaw = req.query.curr_end;
const shiftRaw = req.query.shift;

if (!isValidIsoDateTime(currStartRaw) || !isValidIsoDateTime(currEndRaw) || !isValidIsoDuration(shiftRaw)) {
Copy link
Member

Choose a reason for hiding this comment

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

I don't have a problem with the new checks but I want to record that we don't do them in other open routes. This could be made into an issue for the future if you agree.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah sounds good, I'd be open to working on the issue as well if need be


mocha.describe('Error Handling', () => {
mocha.it('should handle database connection errors gracefully', async () => {
const res = await chai.request(app)
Copy link
Member

Choose a reason for hiding this comment

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

Maybe change the description strings so they more accurately reflect the test?

const res = await chai.request(app)
.get('/api/ciks');

expect([HTTP_CODE.OK, HTTP_CODE.INTERNAL_SERVER_ERROR]).to.include(res.status);
Copy link
Member

Choose a reason for hiding this comment

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

I'm wondering why this and the next test would expect an error code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think I added this by mistake, it was probably because I was running the tests locally very frequently so some failed with server errors. I'll clean this up

@omarraf
Copy link
Contributor Author

omarraf commented Nov 29, 2025

Thanks for the thorough review and commits you made @huss , they're very helpful and I appreciate your time to improve the code. The changes you made look good to me and I'll address the rest of your requested changes soon. Some of my thoughts on your questions:

One area with several comments is if tests could be generalized and the basic code reused across tests

Definitely think it makes sense to consolidate similar validation patterns that could share test logic, but I think it'd be a great follow-up task rather than doing it in this PR since it would be a significant refactor and a seperate PR may be easier to review.

Did you change any of it or can it be included via that PR?

Yeah, the validationHelpers.js I added directly from the previous PR on units.js when I first started this issue. I had left a comment at the top of the file conveying the original author and how the current file would be replaced by that PR. Since then I have built on their work and added several new helper functions (validateCommaSeparatedIdPatterns, expectValidCommaSeparatedIds, validateNoExtraFields, and modified testInvalidField to support multiple expected status codes). I want them to get credit for building the foundation so we can potentially take their original commit and add my modifications on top, or however you'd prefer to handle it.

For the bigger picture items I think we should focus on addressing the rate-limiting problem in CI and doing a thorough audit of all tests vs routes making sure we have complete coverage. For future work we can open up a new issue to do the test generalization and http codes throughout the codebase, but I'm happy to implement in this PR if need be.

@omarraf
Copy link
Contributor Author

omarraf commented Dec 21, 2025

@huss I addressed some of the comments you left, let me know if there's anything else I can change or clarify.

Since this PR has been open for a while and covers a lot of ground, I'd like to wrap it up soon if there aren't any blocking issues. For the bigger refactoring items we discussed, I'm totally open to tackling those in follow-up issues. Same goes for the systematic http code audit and rate-limiting improvements in CI.

Let me know if there's anything else you'd like me to address in this PR. Happy to keep working on this effort either way.

@omarraf
Copy link
Contributor Author

omarraf commented Dec 22, 2025

Regarding the CI test failures, since most appear to be related to rate limiting, would it be possible to configure higher rate limits specifically for the test environment, or is there a preferred approach for handling this in CI? I wanted to check whether that would be considered good practice here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

systematic parameter route testing

2 participants