diff --git a/codeql-workspace.yml b/codeql-workspace.yml index a6408dc26ec..c61313163e5 100644 --- a/codeql-workspace.yml +++ b/codeql-workspace.yml @@ -3,6 +3,7 @@ provide: - "*/ql/lib/qlpack.yml" - "*/ql/test*/qlpack.yml" - "*/ql/upgrade-tests/qlpack.yml" + - "*/ql/downgrade-tests/qlpack.yml" - "*/ql/examples/qlpack.yml" - "*/ql/consistency-queries/qlpack.yml" - "*/ql/automodel/src/qlpack.yml" diff --git a/rust/ql/downgrade-tests/.gitignore b/rust/ql/downgrade-tests/.gitignore new file mode 100644 index 00000000000..3b4d77eb40d --- /dev/null +++ b/rust/ql/downgrade-tests/.gitignore @@ -0,0 +1,3 @@ +*.testproj/ +*.actual +*.log diff --git a/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/.gitignore b/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/.gitignore new file mode 100644 index 00000000000..1abb3d60e26 --- /dev/null +++ b/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/.gitignore @@ -0,0 +1,5 @@ +*.testproj/ +*.actual +*.log +Cargo.toml +lib.rs diff --git a/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/README.md b/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/README.md new file mode 100644 index 00000000000..3cc35fab477 --- /dev/null +++ b/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/README.md @@ -0,0 +1,24 @@ +# Downgrade Regression Test for rust-analyzer 0.0.328 -> 0.0.301 + +This test verifies that the dbscheme downgrade script correctly preserves recoverable data when migrating databases from the new schema back to the old schema. + +## Running the test + +```bash +./run-test.sh +``` + +This will: +1. Build the current extractor +2. Create a database with the new schema from `upgrade_shapes.rs` +3. Validate the new-schema extraction +4. Downgrade the database to the old schema +5. Check out the old commit (491c373e076) +6. Verify that the recovered old-schema properties still match + +## Files + +- `new.ql` / `new.expected`: Query for the new schema (validates extraction) +- `downgraded.ql` / `downgraded.expected`: Query for the downgraded old schema +- `upgrade_shapes.rs`: Rust source containing test shapes for all affected schema elements +- `run-test.sh`: Test runner script diff --git a/rust/ql/upgrade-tests/66a489863649185f4a9770f894505803059a1312/downgraded.expected b/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/downgraded.expected similarity index 87% rename from rust/ql/upgrade-tests/66a489863649185f4a9770f894505803059a1312/downgraded.expected rename to rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/downgraded.expected index 1df9e112bbe..0616c973cb6 100644 --- a/rust/ql/upgrade-tests/66a489863649185f4a9770f894505803059a1312/downgraded.expected +++ b/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/downgraded.expected @@ -1,6 +1,6 @@ formatArgsArgName -| upgrade_shapes.rs:22:37:22:41 | FormatArgsArg | upgrade_shapes.rs:22:37:22:37 | (no string representation) | upgrade_shapes.rs:22:41:22:41 | 1 | 37 | -| upgrade_shapes.rs:22:44:22:48 | FormatArgsArg | upgrade_shapes.rs:22:44:22:44 | (no string representation) | upgrade_shapes.rs:22:48:22:48 | 2 | 44 | +| upgrade_shapes.rs:22:37:22:41 | FormatArgsArg | upgrade_shapes.rs:22:13:22:49 | (no string representation) | upgrade_shapes.rs:22:41:22:41 | 1 | 13 | +| upgrade_shapes.rs:22:44:22:48 | FormatArgsArg | upgrade_shapes.rs:22:13:22:49 | (no string representation) | upgrade_shapes.rs:22:48:22:48 | 2 | 13 | tryBlock | upgrade_shapes.rs:21:13:21:21 | { ... } | structFieldDefault diff --git a/rust/ql/upgrade-tests/66a489863649185f4a9770f894505803059a1312/downgraded.ql b/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/downgraded.ql similarity index 100% rename from rust/ql/upgrade-tests/66a489863649185f4a9770f894505803059a1312/downgraded.ql rename to rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/downgraded.ql diff --git a/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/new.expected b/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/new.expected new file mode 100644 index 00000000000..441d08ab3c3 --- /dev/null +++ b/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/new.expected @@ -0,0 +1,20 @@ +formatArgNamePreserved +| upgrade_shapes.rs:22:37:22:41 | FormatArgsArg | upgrade_shapes.rs:22:37:22:39 | FormatArgsArgName | upgrade_shapes.rs:22:41:22:41 | 1 | 37 | 1 | +| upgrade_shapes.rs:22:44:22:48 | FormatArgsArg | upgrade_shapes.rs:22:44:22:46 | FormatArgsArgName | upgrade_shapes.rs:22:48:22:48 | 2 | 44 | 2 | +tryBlockModifierPreserved +| upgrade_shapes.rs:21:13:21:21 | { ... } | upgrade_shapes.rs:21:13:21:15 | TryBlockModifier | +structFieldDefaultPreserved +| upgrade_shapes.rs:9:5:9:17 | field: u8 | upgrade_shapes.rs:9:17:9:17 | ConstArg | upgrade_shapes.rs:9:17:9:17 | 1 | +variantDiscriminantPreserved +| upgrade_shapes.rs:13:5:13:9 | V | upgrade_shapes.rs:13:9:13:9 | ConstArg | upgrade_shapes.rs:13:9:13:9 | 2 | +pathMetaPreserved +| upgrade_shapes.rs:4:3:4:11 | PathMeta | path_meta | +| upgrade_shapes.rs:7:10:7:18 | PathMeta | path_meta | +keyValueMetaPreserved +| upgrade_shapes.rs:5:3:5:15 | KeyValueMeta | key_value | upgrade_shapes.rs:5:15:5:15 | 1 | +tokenTreeMetaPreserved +| upgrade_shapes.rs:6:3:6:18 | TokenTreeMeta | token_tree | upgrade_shapes.rs:6:13:6:18 | TokenTree | +unsafeMetaPreserved +| upgrade_shapes.rs:7:3:7:19 | UnsafeMeta | upgrade_shapes.rs:7:10:7:18 | PathMeta | path_meta | +traitAliasPreserved +| upgrade_shapes.rs:16:1:18:12 | trait Alias | upgrade_shapes.rs:16:7:16:11 | Alias | upgrade_shapes.rs:16:18:16:22 | ... | upgrade_shapes.rs:17:1:18:11 | WhereClause | diff --git a/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/new.ql b/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/new.ql new file mode 100644 index 00000000000..bd983a8290c --- /dev/null +++ b/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/new.ql @@ -0,0 +1,73 @@ +import codeql.rust.elements + +private predicate inUpgradeShapesFile(Locatable loc) { + loc.getFile().getBaseName() = "upgrade_shapes.rs" +} + +query predicate formatArgNamePreserved( + FormatArgsArg arg, FormatArgsArgName argName, Expr expr, int argNameColumn, string exprText +) { + inUpgradeShapesFile(arg) and + argName = arg.getArgName() and + expr = arg.getExpr() and + argNameColumn = argName.getLocation().getStartColumn() and + exprText = expr.toString() +} + +query predicate tryBlockModifierPreserved(BlockExpr block, TryBlockModifier modifier) { + inUpgradeShapesFile(block) and + modifier = block.getTryBlockModifier() and + modifier.isTry() and + not modifier.hasTypeRepr() +} + +query predicate structFieldDefaultPreserved(StructField field, ConstArg defaultVal, Expr expr) { + inUpgradeShapesFile(field) and + defaultVal = field.getDefaultVal() and + expr = defaultVal.getExpr() +} + +query predicate variantDiscriminantPreserved(Variant variant, ConstArg constArg, Expr expr) { + inUpgradeShapesFile(variant) and + constArg = variant.getConstArg() and + expr = constArg.getExpr() +} + +query predicate pathMetaPreserved(PathMeta meta, string pathText) { + inUpgradeShapesFile(meta) and + pathText = meta.getPath().getText() and + pathText = "path_meta" +} + +query predicate keyValueMetaPreserved(KeyValueMeta meta, string pathText, Expr expr) { + inUpgradeShapesFile(meta) and + pathText = meta.getPath().getText() and + pathText = "key_value" and + expr = meta.getExpr() +} + +query predicate tokenTreeMetaPreserved(TokenTreeMeta meta, string pathText, TokenTree tokenTree) { + inUpgradeShapesFile(meta) and + pathText = meta.getPath().getText() and + pathText = "token_tree" and + tokenTree = meta.getTokenTree() +} + +query predicate unsafeMetaPreserved(UnsafeMeta meta, PathMeta inner, string pathText) { + inUpgradeShapesFile(meta) and + meta.isUnsafe() and + inner = meta.getMeta() and + pathText = inner.getPath().getText() and + pathText = "path_meta" +} + +query predicate traitAliasPreserved( + Trait trait, Name name, TypeBoundList bounds, WhereClause whereClause +) { + inUpgradeShapesFile(trait) and + name = trait.getName() and + name.getText() = "Alias" and + bounds = trait.getTypeBoundList() and + whereClause = trait.getWhereClause() and + not trait.hasAssocItemList() +} diff --git a/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/run-test.sh b/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/run-test.sh new file mode 100755 index 00000000000..48c78127bc5 --- /dev/null +++ b/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/run-test.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +# Manual regression test for the Rust dbscheme downgrade from rust-analyzer 0.0.328 to 0.0.301. +# See README.md for details. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(git rev-parse --show-toplevel)" +OLD_COMMIT="${OLD_COMMIT:-491c373e076}" # origin/main at time of this upgrade +OLD_DBSCHEME="rust/downgrades/109496fd2f20f28a35e50b110859e74882ee80d6/rust.dbscheme" + +cd "$REPO_ROOT" + +if ! git diff --quiet HEAD || [ -n "$(git ls-files --others --exclude-standard)" ]; then + echo "ERROR: Working directory has uncommitted changes." >&2 + echo "Please commit or stash your changes before running this test." >&2 + exit 1 +fi + +ORIGINAL_REF="$(git rev-parse --abbrev-ref HEAD)" +if [ "$ORIGINAL_REF" = "HEAD" ]; then + ORIGINAL_REF="$(git rev-parse HEAD)" +fi + +restore_ref() { + echo "==> Restoring original ref ($ORIGINAL_REF)..." + git checkout --quiet "$ORIGINAL_REF" +} +trap 'restore_ref' EXIT + +echo "==> Building current extractor (this may take a while)..." +bazel run //rust:install + +echo "==> Creating new-schema test database..." +codeql test run \ + --search-path . \ + --keep-databases \ + "$SCRIPT_DIR/new.ql" "$@" + +echo "==> Downgrading dataset to old schema..." +DATASET_DIR=("$SCRIPT_DIR"/*.testproj/db-rust) +if [[ ! -d "${DATASET_DIR[0]}" ]]; then + echo "ERROR: No testproj found at $SCRIPT_DIR/*.testproj" >&2 + exit 1 +fi +codeql dataset upgrade "${DATASET_DIR[0]}" \ + --allow-downgrades \ + --search-path rust \ + --target-dbscheme "$OLD_DBSCHEME" + +echo "==> Checking out old commit ($OLD_COMMIT) for downgrade verification..." +git checkout --quiet "$OLD_COMMIT" +git checkout --quiet "$ORIGINAL_REF" -- rust/ql/downgrade-tests codeql-workspace.yml + +echo "==> Running preservation test on downgraded dataset..." +codeql test run \ + --search-path . \ + --dataset "${DATASET_DIR[0]}" \ + --check-databases \ + "$SCRIPT_DIR/downgraded.ql" "$@" + +restore_ref +trap '' EXIT + +echo "==> All tests passed!" diff --git a/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/upgrade_shapes.rs b/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/upgrade_shapes.rs new file mode 100644 index 00000000000..e64d8f6582c --- /dev/null +++ b/rust/ql/downgrade-tests/66a489863649185f4a9770f894505803059a1312/upgrade_shapes.rs @@ -0,0 +1,23 @@ +#![allow(dead_code)] +#![feature(more_qualified_paths)] + +#[path_meta] +#[key_value = 1] +#[token_tree(list)] +#[unsafe(path_meta)] +struct S { + field: u8 = 1, +} + +enum E { + V = 2, +} + +trait Alias = Clone +where + T: Copy; + +fn f() { + let _ = try { 1 }; + let _ = format_args!("{b} {a}", a = 1, b = 2); +} diff --git a/rust/ql/downgrade-tests/qlpack.yml b/rust/ql/downgrade-tests/qlpack.yml new file mode 100644 index 00000000000..e2e42acf460 --- /dev/null +++ b/rust/ql/downgrade-tests/qlpack.yml @@ -0,0 +1,5 @@ +name: codeql/rust-downgrade-tests +version: 0.0.0 +extractor: rust +dependencies: + codeql/rust-all: ${workspace} diff --git a/rust/ql/upgrade-tests/66a489863649185f4a9770f894505803059a1312/.gitignore b/rust/ql/upgrade-tests/66a489863649185f4a9770f894505803059a1312/.gitignore index 3b4d77eb40d..1abb3d60e26 100644 --- a/rust/ql/upgrade-tests/66a489863649185f4a9770f894505803059a1312/.gitignore +++ b/rust/ql/upgrade-tests/66a489863649185f4a9770f894505803059a1312/.gitignore @@ -1,3 +1,5 @@ *.testproj/ *.actual *.log +Cargo.toml +lib.rs diff --git a/rust/ql/upgrade-tests/66a489863649185f4a9770f894505803059a1312/README.md b/rust/ql/upgrade-tests/66a489863649185f4a9770f894505803059a1312/README.md index a728458bef4..ecc94261ee5 100644 --- a/rust/ql/upgrade-tests/66a489863649185f4a9770f894505803059a1312/README.md +++ b/rust/ql/upgrade-tests/66a489863649185f4a9770f894505803059a1312/README.md @@ -1,6 +1,6 @@ # Upgrade Regression Test for rust-analyzer 0.0.301 → 0.0.328 -This test verifies that the dbscheme upgrade and downgrade scripts correctly preserve data when migrating databases between the old and new schemas. +This test verifies that the dbscheme upgrade script correctly preserves data when migrating databases from the old schema to the new schema. ## Running the test @@ -16,13 +16,10 @@ This will: 5. Restore your branch 6. Upgrade the database to the new schema 7. Verify that the old properties are still accessible via the new schema -8. Downgrade the database back to the old schema -9. Verify that the recovered old-schema properties still match ## Files -- `old.ql` / `old.expected`: Query for the old schema (validates extraction and downgrade) +- `old.ql` / `old.expected`: Query for the old schema (validates extraction) - `new.ql` / `new.expected`: Query for the new schema (validates upgrade preserved data) -- `downgraded.ql` / `downgraded.expected`: Query for the downgraded old schema - `upgrade_shapes.rs`: Rust source containing test shapes for all affected schema elements - `run-test.sh`: Test runner script diff --git a/rust/ql/upgrade-tests/66a489863649185f4a9770f894505803059a1312/run-test.sh b/rust/ql/upgrade-tests/66a489863649185f4a9770f894505803059a1312/run-test.sh index 1dbbf2783b7..b5ae0d8a42f 100755 --- a/rust/ql/upgrade-tests/66a489863649185f4a9770f894505803059a1312/run-test.sh +++ b/rust/ql/upgrade-tests/66a489863649185f4a9770f894505803059a1312/run-test.sh @@ -7,7 +7,6 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(git rev-parse --show-toplevel)" OLD_COMMIT="${OLD_COMMIT:-491c373e076}" # origin/main at time of this upgrade -OLD_DBSCHEME="rust/downgrades/109496fd2f20f28a35e50b110859e74882ee80d6/rust.dbscheme" cd "$REPO_ROOT" @@ -65,26 +64,4 @@ codeql test run \ --check-databases \ "$SCRIPT_DIR/new.ql" "$@" -echo "==> Downgrading dataset back to old schema..." -codeql dataset upgrade "${DATASET_DIR[0]}" \ - --allow-downgrades \ - --search-path rust \ - --target-dbscheme "$OLD_DBSCHEME" - -trap 'restore_ref' EXIT - -echo "==> Checking out old commit ($OLD_COMMIT) for downgrade verification..." -git checkout --quiet "$OLD_COMMIT" -git checkout --quiet "$ORIGINAL_REF" -- rust/ql/upgrade-tests codeql-workspace.yml - -echo "==> Running preservation test on downgraded dataset..." -codeql test run \ - --search-path . \ - --dataset "${DATASET_DIR[0]}" \ - --check-databases \ - "$SCRIPT_DIR/downgraded.ql" "$@" - -restore_ref -trap '' EXIT - echo "==> All tests passed!"