Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
fc516a5
feat(cli): Add program ID mismatch check before building
swaroop-osec Oct 23, 2025
f85a0b8
feat(cli): Skip program ID mismatch check if --skip-lint is used
swaroop-osec Oct 23, 2025
8eb0895
chore(tests): Add --skip-lint option to anchor build command
swaroop-osec Oct 23, 2025
00c0406
fix(tests): Sync keys before building programs in safety checks
swaroop-osec Oct 23, 2025
aee5b8b
fix(cli): Update program ID mismatch message to include '--skip-lint'…
swaroop-osec Oct 23, 2025
84d1d6d
chore(tests): Fix safety-checks test
swaroop-osec Oct 23, 2025
70e98e5
fix(tests): Fix typescript error
swaroop-osec Oct 23, 2025
00b2178
chore(tests): Add cleanup commands to safety-checks test
swaroop-osec Oct 23, 2025
0f59f0b
refactor(tests): Update confirmation options in CPI return and events…
swaroop-osec Oct 23, 2025
c7606e7
refactor(tests): prettier
swaroop-osec Oct 23, 2025
b289fe2
feat(cli): Introduce --ignore-keys option to skip program ID mismatch…
swaroop-osec Oct 24, 2025
103b06b
refactor(tests): Restore test.sh from master
swaroop-osec Oct 24, 2025
7da9bfc
fix(tests): Update safety-checks test to use --ignore-keys
swaroop-osec Oct 24, 2025
94567f9
Merge branch 'master' into feat/issue-3985
swaroop-osec Oct 24, 2025
be62982
refactor(cli): Clippy Fixes
swaroop-osec Oct 24, 2025
b6296dd
chore(tutorial): Update test script to include --ignore-keys option a…
swaroop-osec Oct 24, 2025
81671e3
fix(tests): Format bench.json
swaroop-osec Oct 24, 2025
00232ad
fix(tests): Add --ignore-keys option to stack-memory test build command
swaroop-osec Oct 24, 2025
0eb5a9c
fix(tests): Remove newline at end of bench.json
swaroop-osec Oct 24, 2025
473a55a
fix(tests): Format stack-memory.ts
swaroop-osec Oct 24, 2025
ee50cd7
feat(docs): Update CHANGELOG.md
swaroop-osec Oct 24, 2025
1ddbe4b
fix(tests): Set ignore_keys to true in anchor test
swaroop-osec Nov 6, 2025
96b39de
fix(tests): Remove --ignore-keys option from anchor test
swaroop-osec Nov 6, 2025
5d362d1
feat(cli): Updated docs
swaroop-osec Nov 6, 2025
ea8b254
refactor(cli): Fix clippy warnings
swaroop-osec Nov 6, 2025
dc40703
Merge branch 'master' into feat/issue-3985
jacobcreech Nov 27, 2025
1ff62e4
chore: fix merge conflict
jacobcreech Nov 27, 2025
686dde0
fix: merge conflict
jacobcreech Nov 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/reusable-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ jobs:
path: tests/safety-checks
- cmd: cd tests/custom-coder && anchor test --skip-lint && npx tsc --noEmit
path: tests/custom-coder
- cmd: cd tests/custom-discriminator && anchor test
- cmd: cd tests/custom-discriminator && anchor test --skip-lint && npx tsc --noEmit
path: tests/custom-discriminator
- cmd: cd tests/validator-clone && anchor test --skip-lint && npx tsc --noEmit
path: tests/validator-clone
Expand All @@ -460,7 +460,7 @@ jobs:
path: tests/bench
- cmd: cd tests/idl && ./test.sh
path: tests/idl
- cmd: cd tests/lazy-account && anchor test
- cmd: cd tests/lazy-account && anchor test --skip-lint
path: tests/lazy-account
steps:
- uses: actions/checkout@v3
Expand Down
50 changes: 50 additions & 0 deletions cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1317,6 +1317,11 @@ pub fn build(
check_anchor_version(&cfg).ok();
check_deps(&cfg).ok();

// Check for program ID mismatches before building (skip if --skip-lint is used)
if !skip_lint {
check_program_id_mismatch(&cfg, program_name.clone())?;
}

let idl_out = match idl {
Some(idl) => Some(PathBuf::from(idl)),
None => Some(cfg_parent.join("target").join("idl")),
Expand Down Expand Up @@ -4236,6 +4241,51 @@ fn keys_sync(cfg_override: &ConfigOverride, program_name: Option<String>) -> Res
})
}

/// Check if there's a mismatch between the program keypair and the `declare_id!` in the source code.
/// Returns an error if a mismatch is detected, prompting the user to run `anchor keys sync`.
fn check_program_id_mismatch(cfg: &WithPath<Config>, program_name: Option<String>) -> Result<()> {
let declare_id_regex = RegexBuilder::new(r#"^(([\w]+::)*)declare_id!\("(\w*)"\)"#)
.multi_line(true)
.build()
.unwrap();

for program in cfg.get_programs(program_name)? {
// Get the pubkey from the keypair file
let actual_program_id = program.pubkey()?.to_string();

// Check declaration in program files
let src_path = program.path.join("src");
let files_to_check = vec![src_path.join("lib.rs"), src_path.join("id.rs")];

for path in files_to_check {
let content = match fs::read_to_string(&path) {
Ok(content) => content,
Err(_) => continue,
};

let incorrect_program_id = declare_id_regex
.captures(&content)
.and_then(|captures| captures.get(3))
.filter(|program_id_match| program_id_match.as_str() != actual_program_id);

if let Some(program_id_match) = incorrect_program_id {
let declared_id = program_id_match.as_str();
return Err(anyhow!(
"Program ID mismatch detected for program '{}':\n \
Keypair file has: {}\n \
Source code has: {}\n\n\
Please run 'anchor keys sync' to update the program ID in your source code or use the '--skip-lint' flag to skip the lint checks.",
program.lib_name,
actual_program_id,
declared_id
));
}
}
}

Ok(())
}

fn localnet(
cfg_override: &ConfigOverride,
skip_build: bool,
Expand Down
10 changes: 5 additions & 5 deletions client/example/run-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ main() {
local events_pid="2dhGsWUzy5YKUsjZdLHLmkNpUDAXkNa9MYWsPc4Ziqzy"
local optional_pid="FNqz6pqLAwvMSds2FYjR4nKV3moVpPNtvkfGFrqLKrgG"

cd ../../tests/composite && anchor build && cd -
cd ../../tests/composite && anchor build --skip-lint && cd -
[ $? -ne 0 ] && exit 1
cd ../../examples/tutorial/basic-2 && anchor build && cd -
cd ../../examples/tutorial/basic-2 && anchor build --skip-lint && cd -
[ $? -ne 0 ] && exit 1
cd ../../examples/tutorial/basic-4 && anchor build && cd -
cd ../../examples/tutorial/basic-4 && anchor build --skip-lint && cd -
[ $? -ne 0 ] && exit 1
cd ../../tests/events && anchor build && cd -
cd ../../tests/events && anchor build --skip-lint && cd -
[ $? -ne 0 ] && exit 1
cd ../../tests/optional && anchor build && cd -
cd ../../tests/optional && anchor build --skip-lint && cd -
[ $? -ne 0 ] && exit 1

#
Expand Down
2 changes: 1 addition & 1 deletion tests/custom-discriminator/tests/custom-discriminator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe("custom-discriminator", () => {
"confirmed"
);
const myAccount = await program.account.myAccount.fetch(
pubkeys.myAccount
pubkeys.myAccount as anchor.web3.PublicKey
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🤔 What change caused this to be needed?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Tbh I really have no idea some times the typescript raises errors. And the tests were passed locally without this change. Another example

);
assert.strictEqual(myAccount.field, field);
});
Expand Down
13 changes: 11 additions & 2 deletions tests/safety-checks/Anchor.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
[toolchain]

[features]
resolution = true
skip-lint = false

[programs.localnet]
unchecked_account = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
account_info = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
account_info = "99YPYSHjNekPHmMB7yrTxZCV2k2pRMKEqwwcqE62NqdA"
unchecked_account = "4es8ojkX4URUyar2pbuLXQ4WoFtUizb5EupfaEgHjYQF"

[registry]
url = "https://api.apr.dev"

[provider]
cluster = "localnet"
Expand Down
2 changes: 1 addition & 1 deletion tests/safety-checks/programs/unchecked-account/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2018"

[lib]
crate-type = ["cdylib", "lib"]
name = "safety_checks"
name = "unchecked_account"

[features]
no-entrypoint = []
Expand Down
50 changes: 28 additions & 22 deletions tests/safety-checks/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,42 @@

echo "Building programs"

#
# Build the UncheckedAccount variant.
#
pushd programs/unchecked-account/
output=$(anchor build 2>&1 > /dev/null)
mkdir -p tmp

# Test unchecked-account
mv programs/account-info tmp/
mv programs/ignore-non-accounts tmp/
output=$(anchor keys sync && anchor build 2>&1 > /dev/null)
if ! [[ $output =~ "Struct field \"unchecked\" is unsafe" ]]; then
echo "Error: expected /// CHECK error"
echo "Error: expected /// CHECK error in programs/unchecked-account"
exit 1
fi
popd
mv tmp/account-info programs/
mv tmp/ignore-non-accounts programs/

#
# Build the AccountInfo variant.
#
pushd programs/account-info/
output=$(anchor build 2>&1 > /dev/null)
# Test account-info
mv programs/unchecked-account tmp/
mv programs/ignore-non-accounts tmp/
output=$(anchor keys sync && anchor build 2>&1 > /dev/null)
if ! [[ $output =~ "Struct field \"unchecked\" is unsafe" ]]; then
echo "Error: expected /// CHECK error"
echo "Error: expected /// CHECK error in programs/account-info"
exit 1
fi
popd

#
# Build the control variant.
#
pushd programs/ignore-non-accounts/
if ! anchor build ; then
echo "Error: anchor build failed when it shouldn't have"
mv tmp/unchecked-account programs/
mv tmp/ignore-non-accounts programs/

# Test ignore-non-accounts
mv programs/unchecked-account tmp/
mv programs/account-info tmp/
if ! anchor keys sync && anchor build ; then
echo "Error: anchor build failed when it shouldn't have in programs/ignore-non-accounts"
exit 1
fi
popd
mv tmp/unchecked-account programs/
mv tmp/account-info programs/

rmdir tmp

git reset --hard

echo "Success. As expected, all builds failed that were supposed to fail."
Loading