Skip to content

Conversation

@jribbink
Copy link
Contributor

@jribbink jribbink commented Dec 16, 2025

Closes #2224
Closes #2225

Description

Adds support for the SkipUpdatePrompts flag, and add support for dependency filesystem changes during deferred dependency prompts. Additionally adds support for the Update flag.

This is comparable to a y/n/prompt state, where:

  • Update => y
  • SkipUpdatePrompts => n
  • default => prompt

Test cases:

  • First install, up-to-date hashes => no prompt, install, no hash change
  • First install, outdated hashes => prompt, YES => install, hash change || NO => no install, no hash change
  • Already installed, up-to-date hashes => no-prompt, install, no hash change
  • Already installed, outdated hashes => prompt, YES => install, hash change || NO => no install, no hash change (IF NOT MATCHING => show error SECURITY -- we cannot fetch old hash yet, if MATCHING allow unchanged dep)
  • Edge case, prompts disabled, first install

Additionally - hash integrity validation (such that local file matches the flow.json hash) has been added to prevent these files from going out of sync.


For contributor use:

  • Targeted PR against master branch
  • Linked to Github issue with discussion and accepted design OR link to spec that describes this work
  • Code follows the standards mentioned here
  • Updated relevant documentation
  • Re-reviewed Files changed in the Github PR explorer
  • Added appropriate labels

@github-actions
Copy link

github-actions bot commented Dec 16, 2025

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@jribbink jribbink force-pushed the jribbink/fix-prompts branch from 1f648b3 to 6c95655 Compare December 16, 2025 20:06
@codecov-commenter
Copy link

codecov-commenter commented Dec 16, 2025

Codecov Report

❌ Patch coverage is 75.75758% with 24 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/dependencymanager/dependencyinstaller.go 75.75% 19 Missing and 5 partials ⚠️

📢 Thoughts on this report? Let us know!

@jribbink jribbink marked this pull request as ready for review December 16, 2025 20:43
@jribbink jribbink marked this pull request as draft December 16, 2025 20:46
@jribbink jribbink marked this pull request as ready for review December 16, 2025 20:46
@jribbink jribbink added the Improvement Technical work without new features, refactoring, improving tests label Dec 16, 2025
@jribbink jribbink marked this pull request as draft December 16, 2025 23:26
@jribbink jribbink marked this pull request as ready for review December 17, 2025 00:47
@jribbink jribbink marked this pull request as draft December 17, 2025 00:52
@jribbink jribbink marked this pull request as ready for review December 17, 2025 01:04
@jribbink jribbink marked this pull request as draft December 17, 2025 02:34
@jribbink jribbink marked this pull request as ready for review December 18, 2025 06:40
Comment on lines 1012 to 1014
// File exists - keep it at current version
msg := util.MessageWithEmojiPrefix("⏸️", fmt.Sprintf("%s kept at current version", pending.contractName))
di.logs.stateUpdates = append(di.logs.stateUpdates, msg)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is not correct. We have no guarantee that the stored file hash matches the flow.json hash at this point.

However, files are stored in a processed state, and flow.json hashes are stored in the pre-processed state, so validation becomes tricky.

Copy link
Contributor Author

@jribbink jribbink Dec 19, 2025

Choose a reason for hiding this comment

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

I think I got it 6c775c7

But this required changing the hashing function to consume the processed imports. Because of the fact that further dependencies are processed/handled independently anyways, and the contracts are only every used by DM in their processed representation, it seems safe to make this change.

NOTE: This will require a migration step, all devs on teams sharing projects will need to update their CLI to prevent the hash from constantly changing back and forth.

cc @chasefleming

)

var analyzers = maps.Values(cdclint.Analyzers)
// getAnalyzers returns analyzers in deterministic order (sorted by name)
Copy link
Contributor Author

@jribbink jribbink Dec 19, 2025

Choose a reason for hiding this comment

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

Had flakey tests due to non-determinism here, was introduced in prior PR just never saw it yet. Might as well fix it now.

@chasefleming chasefleming requested a review from Copilot December 19, 2025 21:24
Copy link
Member

@turbolent turbolent left a comment

Choose a reason for hiding this comment

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

Thank you for improving this!

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements support for dependency update management through two new flags (--update and --skip-update-prompts) that control how the CLI handles outdated dependency hashes. The implementation adds validation to detect hash mismatches between local files and on-chain contracts, ensuring dependency integrity when users decline updates or skip prompts. Additionally, it includes a fix to ensure deterministic ordering of linters by sorting analyzer keys.

Key Changes

  • Added mutually exclusive flags --update (auto-accept updates) and --skip-update-prompts (auto-decline updates) with validation
  • Enhanced dependency installation to detect and handle hash mismatches with appropriate error messages and file system operations
  • Fixed non-deterministic linter behavior by sorting analyzer keys before execution

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
internal/dependencymanager/dependencyinstaller_test.go Adds comprehensive test coverage for dependency installation scenarios including fresh clones, outdated hashes, and flag behaviors
internal/dependencymanager/dependencyinstaller.go Implements update flag logic, hash validation, file integrity checks, and deferred prompt handling with filesystem operations
internal/cadence/linter.go Replaces non-deterministic map iteration with sorted key ordering for consistent linter results

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

modifiedContractCode := []byte(`access(all) contract Hello { access(all) fun sayHello(): String { return "Hello, Modified!" } }`)
newContractCode := []byte(`access(all) contract Hello { access(all) fun sayHello(): String { return "Hello, World! v2" } }`)

// Calculate the old hash (of the converted contract)
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

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

Corrected spelling of 'converted' to 'committed'.

Suggested change
// Calculate the old hash (of the converted contract)
// Calculate the old hash (of the committed contract)

Copilot uses AI. Check for mistakes.
Comment on lines +631 to +633
// Calculate hash of converted contract (what gets written to disk)
// This is what we store in flow.json so we can verify file integrity later
// Imported contracts are still checked for consistency by traversing the dependency tree.
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

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

The comment on line 633 about 'Imported contracts' seems unclear in this context. Consider clarifying how imported contracts relate to the hash calculation being performed here, or remove this line if it's not directly relevant to the hash calculation logic.

Suggested change
// Calculate hash of converted contract (what gets written to disk)
// This is what we store in flow.json so we can verify file integrity later
// Imported contracts are still checked for consistency by traversing the dependency tree.
// Calculate hash of the converted contract source (the code that gets written to disk).
// This hash is stored in flow.json so we can later verify that the on-disk contract
// matches the version that was originally installed. Note that this hash only covers
// the primary contract; any imported contracts are validated separately as part of
// the dependency tree traversal logic elsewhere in the dependency manager.

Copilot uses AI. Check for mistakes.
// User chose not to update
// If file doesn't exist, we MUST fail - can't guarantee frozen deps (no way to fetch old version)
if !di.contractFileExists(pending.contractAddr, pending.contractName) {
return fmt.Errorf("dependency %s has changed on-chain but file does not exist locally. Cannot keep at current version because we have no way to fetch the old version from the blockchain. Either accept the update or manually add the contract file", pending.contractName)
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

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

This error message is quite long and could be more user-friendly. Consider breaking it into multiple lines or simplifying the explanation to improve readability.

Suggested change
return fmt.Errorf("dependency %s has changed on-chain but file does not exist locally. Cannot keep at current version because we have no way to fetch the old version from the blockchain. Either accept the update or manually add the contract file", pending.contractName)
return fmt.Errorf(
"dependency %s has changed on-chain, but the local contract file does not exist.\n"+
"Cannot keep the current version because the previous on-chain code cannot be fetched.\n"+
"Either accept the update or manually add the contract file.",
pending.contractName,
)

Copilot uses AI. Check for mistakes.
@chasefleming chasefleming requested a review from Copilot December 23, 2025 00:08
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@jribbink jribbink merged commit e7ae0ce into master Dec 23, 2025
9 checks passed
@jribbink jribbink deleted the jribbink/fix-prompts branch December 23, 2025 02:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Improvement Technical work without new features, refactoring, improving tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Declining dependency update prompts does not install contracts flow dependencies install --skip-update-prompts does not work

5 participants