-
Notifications
You must be signed in to change notification settings - Fork 0
refactor: keep SQL out of the beacon's browser bundle #113
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
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import { describe, expect, it } from "vitest"; | ||
|
|
||
| import { beaconParameters, defaultBeaconPath } from "./beacon-events.js"; | ||
| import { | ||
| aBeaconEvent, | ||
| beaconEventColumn, | ||
| outsideTheBeaconPath, | ||
| } from "./beacon-rows.js"; | ||
|
|
||
| describe("reading a beacon event off a row", () => { | ||
| it("reads a row's event back off the column CloudFront wrote it to", () => { | ||
| // Given the SQL a rollup selects the event with. | ||
| // Then it reads the query string, which is where the payload is. No | ||
| // column of the table holds it, because a table column is a CloudFront | ||
| // field and CloudFront has no field for somebody else's payload. | ||
| expect(beaconEventColumn).toContain("cs_uri_query"); | ||
| expect(beaconEventColumn).toContain(`'${beaconParameters.event}'`); | ||
| }); | ||
|
|
||
| it("counts only requests carrying an envelope", () => { | ||
| // Given the conditions a rollup filters beacon rows with. | ||
| // Then a request to the beacon's path with no version parameter is left | ||
| // out. A crawler that found the URL in a page's source sends one of | ||
| // those, and counting it would report an event nobody caused. | ||
| expect(aBeaconEvent).toContain("cs_uri_query <> '-'"); | ||
| expect(aBeaconEvent.join(" ")).toContain(`'${beaconParameters.version}'`); | ||
| }); | ||
|
|
||
| it("names the path where the envelope's own conditions leave it out", () => { | ||
| // Given the condition status-codes takes the beacon's requests back out | ||
| // with. | ||
| // Then it names the path, where `aBeaconEvent` leaves the path to the | ||
| // request's own `paths`. The two run in opposite directions. It reads | ||
| // the column as delivered, since the path carries nothing a browser or | ||
| // CloudFront escapes. | ||
| expect(outsideTheBeaconPath).toContain(`'${defaultBeaconPath}'`); | ||
| expect(outsideTheBeaconPath).not.toContain("url_decode"); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| // Reading a beacon event back off the rows CloudFront wrote. | ||
| // | ||
| // Apart from `beacon-events.ts` because the two halves have different | ||
| // readers. That module builds a query string inside a browser and this one | ||
| // builds SQL for Athena, and a site folding the beacon into its own bundle | ||
| // was carrying both. KensioSoftware/rainlytics#110 measured what that cost | ||
| // and split them. | ||
| // | ||
| // The payload stays in `cs_uri_query` and is read at query time, the way | ||
| // `searches` already reads a search term out of the same column. #100 settled | ||
| // that, and `beacon-events.ts` carries the rest of the reasoning along with | ||
| // the parameter names these expressions read. | ||
|
|
||
| import { decodedParameter } from "./log-encoding.js"; | ||
| import { quoted } from "./sql-text.js"; | ||
|
|
||
| import { beaconParameters, defaultBeaconPath } from "./beacon-events.js"; | ||
|
|
||
| /** The envelope version a row was written under, as SQL. */ | ||
| export const beaconVersionColumn = decodedParameter(beaconParameters.version); | ||
|
|
||
| /** What happened, as SQL. */ | ||
| export const beaconEventColumn = decodedParameter(beaconParameters.event); | ||
|
|
||
| /** The page it happened on, as SQL. */ | ||
| export const beaconPageColumn = decodedParameter(beaconParameters.page); | ||
|
|
||
| /** | ||
| * The rows a beacon event is, as conditions for `rowsFor`. | ||
| * | ||
| * The path is not among them. A rollup narrows to the beacon's path through | ||
| * the request's own `paths`, the way any other question narrows to a section | ||
| * of a site, and a site that moved its beacon then says so in one place. | ||
| * | ||
| * These leave out anything else reaching the same path. A crawler following | ||
| * a beacon URL out of a page's source carries no version parameter, and the | ||
| * bot filter `rowsFor` applies has already taken most of them. | ||
| * | ||
| * ```typescript | ||
| * rowsFor({ ...request, paths: [defaultBeaconPath] }, aBeaconEvent); | ||
| * ``` | ||
| */ | ||
| export const aBeaconEvent: readonly string[] = [ | ||
| "cs_method = 'GET'", | ||
| "cs_uri_query <> '-'", | ||
| `${beaconVersionColumn} <> ''`, | ||
| ]; | ||
|
|
||
| /** | ||
| * The rows outside the beacon's path, as a condition for `rowsFor`. | ||
| * | ||
| * The other direction from {@link aBeaconEvent}, and it names the path that | ||
| * one leaves out. A question about beacon events narrows to the beacon | ||
| * through the request's own `paths`. A question about what the site answered | ||
| * has to take the beacon's requests back out, and `status-codes` is the one | ||
| * that does. | ||
| * | ||
| * Matched against the column as CloudFront delivered it, where `--path` | ||
| * decodes twice first. The path here is a constant this package chose and it | ||
| * carries nothing a browser or CloudFront escapes, so a record holds it as it | ||
| * was sent. An address somebody typed can hold anything. | ||
| * | ||
| * A prefix, the way every path match in Rainlytics is one. | ||
| */ | ||
| export const outsideTheBeaconPath = `strpos(cs_uri_stem, ${quoted( | ||
| defaultBeaconPath, | ||
| )}) <> 1`; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
Repository: KensioSoftware/rainlytics
Length of output: 214
🏁 Script executed:
Repository: KensioSoftware/rainlytics
Length of output: 8666
Make the envelope import check multiline-aware.
grepapplies this pattern one line at a time, so it misses valid dynamic imports with a line break, such asimport(\n "./heavy.js"). Use a JavaScript-aware parser or token-aware scan, and add a regression fixture.🤖 Prompt for AI Agents