Skip to content

Made advancements in cgc bundle (.cgc format) - #1060

Merged
Shashankss1205 merged 2 commits into
CodeGraphContext:mainfrom
tejinderpa:fix/cgc_bundle
Aug 13, 2026
Merged

Shashankss1205 merged 2 commits into
CodeGraphContext:mainfrom
tejinderpa:fix/cgc_bundle

Conversation

@tejinderpa

Copy link
Copy Markdown
Contributor

fixes #955
This PR improves the .cgc bundle format with security and comparison features that were previously listed as roadmap/future work.

What Changed

  • Added SHA-256 bundle manifests for integrity verification.
  • Added optional HMAC-SHA256 signing for trusted bundle verification.
  • Added optional AES-256-GCM encryption for password-protected bundles.
  • Added safe extraction support for plaintext and encrypted .cgc archives.
  • Added bundle inspection and verification helpers.
  • Added native bundle diffing so two .cgc files can be compared without importing them.
  • Added CLI commands:
    • cgc bundle verify
    • cgc bundle inspect
    • cgc bundle diff
  • Extended existing commands with security options:
    • cgc bundle export --sign-key ...
    • cgc bundle export --encrypt-password ...
    • cgc bundle import --password ... --verify-key ...
    • cgc bundle load --password ... --verify-key ...
  • Added cryptography>=42.0.0 as a dependency for encrypted bundle support.

Why

The current .cgc format worked well for basic full-snapshot sharing, but it lacked several production-grade features:

  • Integrity checks
  • Trusted-source verification
  • Encrypted sharing for sensitive code graphs
  • Native bundle comparison

This PR makes .cgc bundles safer to distribute and easier to compare across project versions.

Verification

  • Ran Python syntax checks on edited files:
    • src/codegraphcontext/core/cgc_bundle.py
    • src/codegraphcontext/cli/main.py
  • Tested synthetic signed bundle verification.
  • Tested signed bundle diff with verification key.
  • Tested encrypted bundle verification.
  • Confirmed encrypted .cgc archives only contain:
    • encryption.json
    • payload.enc

Notes

This PR does not fully implement registry publishing, database-level conflict resolution, or delta import/application yet. It lays the groundwork for those features by adding manifest-based verification and bundle comparison.

Copilot AI review requested due to automatic review settings June 3, 2026 07:15
@github-project-automation github-project-automation Bot moved this to Backlog tasks in CGC Progress Board Jun 3, 2026
@vercel

vercel Bot commented Jun 3, 2026

Copy link
Copy Markdown

@tejinderpa is attempting to deploy a commit to the shashankss1205's projects Team on Vercel.

A member of the Team first needs to authorize it.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds security and portability features to CGC bundle export/import by introducing integrity manifests, optional HMAC signing, and optional AES-GCM encryption, plus CLI commands to verify/inspect/diff bundles and improved parsing heuristics for large files.

Changes:

  • Add manifest generation + optional HMAC signature and AES-256-GCM “envelope” encryption to bundle export/import.
  • Extend CLI with bundle verify/inspect/diff commands and new flags for signing/encryption.
  • Adjust web parser worker to skip large files with different thresholds for likely-minified vs normal sources.

Reviewed changes

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

File Description
website/src/lib/parser.worker.ts Adds size thresholds and heuristics to skip overly large / likely-minified files during parsing.
src/codegraphcontext/core/cgc_bundle.py Implements manifest checksums, optional HMAC signing, optional AES-GCM encryption envelope, and verify/inspect/diff helpers.
src/codegraphcontext/cli/main.py Exposes signing/encryption options and adds verify/inspect/diff CLI subcommands.
pyproject.toml Adds cryptography dependency to support encrypted bundles.

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

Comment on lines +887 to +897
def _extract_zip_safely(self, zip_path: Path, target_dir: Path) -> Tuple[bool, str]:
target_root = target_dir.resolve()
with zipfile.ZipFile(zip_path, "r") as zip_ref:
for entry in zip_ref.namelist():
resolved = (target_dir / entry).resolve()
try:
resolved.relative_to(target_root)
except ValueError:
return False, f"Zip Slip detected: entry '{entry}' escapes target directory"
zip_ref.extractall(target_dir)
return True, "Extracted"
Comment on lines +933 to +939
salt = base64.b64decode(metadata["salt"])
nonce = base64.b64decode(metadata["nonce"])
key = self._derive_encryption_key(password, salt, int(metadata.get("iterations", 390000)))
try:
plaintext = AESGCM(key).decrypt(nonce, ciphertext, None)
except Exception:
return None, "Failed to decrypt bundle payload"
Comment on lines +864 to +869
salt = secrets.token_bytes(16)
nonce = secrets.token_bytes(12)
iterations = 390000
key = self._derive_encryption_key(password, salt, iterations)
plaintext = payload_zip.read_bytes()
ciphertext = AESGCM(key).encrypt(nonce, plaintext, None)
Comment on lines +747 to +752
manifest = {
"manifest_version": "1.0.0",
"digest": "sha256",
"files": files,
"created_at": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
}
output: str = typer.Argument(..., help="Output path for the .cgc bundle file"),
repo: Optional[str] = typer.Option(None, "--repo", "-r", help="Specific repository path to export (default: export all)"),
no_stats: bool = typer.Option(False, "--no-stats", help="Skip statistics generation"),
sign_key: Optional[str] = typer.Option(None, "--sign-key", envvar="CGC_BUNDLE_SIGN_KEY", help="HMAC signing key (or set CGC_BUNDLE_SIGN_KEY)"),
Comment on lines +663 to +664
password: Optional[str] = typer.Option(None, "--password", envvar="CGC_BUNDLE_PASSWORD", help="Password for encrypted bundles (or set CGC_BUNDLE_PASSWORD)", hide_input=True),
verify_key: Optional[str] = typer.Option(None, "--verify-key", envvar="CGC_BUNDLE_VERIFY_KEY", help="HMAC verification key for signed bundles (or set CGC_BUNDLE_VERIFY_KEY)"),
Comment thread pyproject.toml
Comment on lines +39 to +40
"uvicorn>=0.22.0",
"cryptography>=42.0.0"
Comment on lines +846 to +851
const isLikelyMinified = /\.min\.[cm]?[jt]sx?$/.test(f.path) || /(^|[\/\\])(vendor|lib)[\/\\]/.test(f.path);
const maxFileChars = isLikelyMinified ? MAX_PARSEABLE_MINIFIED_FILE_CHARS : MAX_PARSEABLE_FILE_CHARS;

if (f.content.length > maxFileChars || isPathIgnored) {
if (f.content.length > maxFileChars) {
console.warn(`[Diagnostic] Skipping very large file (${(f.content.length / 1024).toFixed(1)} KB, limit ${(maxFileChars / 1024).toFixed(0)} KB): ${f.path}`);
@tejinderpa

Copy link
Copy Markdown
Contributor Author

Hey it is asking for permissions, kindly grant it so that i see if any conflicts are there...than resolve them and if no conflicts occur kindly merge it @Shashankss1205

@Shashankss1205

Copy link
Copy Markdown
Collaborator

👋 Thanks for contributing to CodeGraphContext! Since this PR was opened, main has moved forward significantly (we just shipped v0.5.2 and merged ~50 PRs), so this one now has merge conflicts. Could you please rebase onto the latest main and resolve the conflicts? Once it is conflict-free and CI is green, we will review and merge it. Really appreciate your work — thank you! 🙏

@Shashankss1205

Copy link
Copy Markdown
Collaborator

Triage update: bundle integrity manifests, signing, and native .cgc diffing (#955, and #1312 asks for exactly the diff piece) are all still wanted. cgc_bundle.py has been heavily reworked since this branch (multi-backend PK maps, Zip Slip protection, identifier validation), so this needs a careful rebase — security-sensitive code we don't want to merge mechanically. @tejinderpa still up for rebasing it? Happy to review promptly if so. 🙏

@Shashankss1205

Copy link
Copy Markdown
Collaborator

Reviewed this properly and I'm handing it back rather than resolving the conflicts myself — with one piece of good news and one thing that needs your decision.

The good news: your Zip Slip protection is sound

The conflict in cgc_bundle.py looked alarming, because your _extract_bundle_archive replaces a block that main has since hardened against path traversal. A careless "take the PR side" resolution would have silently reintroduced the vulnerability.

It does not. _extract_zip_safely carries equivalent protection:

resolved = (target_dir / entry).resolve()
try:
    resolved.relative_to(target_root)
except ValueError:
    return False, f"Zip Slip detected: entry '{entry}' escapes target directory"

That is arguably stronger than main's check — relative_to also covers the target-equals-root case. And you correctly apply it to the inner payload zip after decryption, which is the step an attacker would actually target. Nicely done.

Why I stopped

Two reasons.

1. The conflicts are not mechanical. 23 commits have landed on cgc_bundle.py since you branched, and there are 9 conflict hunks across two files. I tried resolving main.py by keeping both sides — the natural reading, since your hunks add CLI options where main added nothing — and it produced a syntax error (unmatched ')' at line 1154). So at least one hunk overlaps a signature main also changed, and getting it wrong silently is easy.

2. This is a design decision, not a merge. The PR introduces HMAC-SHA256 signing and AES-256-GCM encryption to the bundle format. That is a format and threat-model commitment: once bundles carry an envelope, every consumer must understand it, and the choices below become the project's answers.

Questions worth settling before it lands, all of which are yours rather than mine:

  • Key handling. Keys arrive via --sign-key / CGC_BUNDLE_SIGN_KEY. Env vars leak into process listings and CI logs; is that the intended surface, or should there be a keyfile path?
  • KDF cost. iterations defaults to 390000 and is read from the bundle's own metadata at decrypt time. An attacker-supplied bundle can therefore set it to 1. Worth clamping to a floor.
  • Backwards compatibility. Can 0.5.7 read a bundle written by this branch, and vice versa? The registry ships published bundles, so a format change needs an answer either way.
  • Scope. .cgc format advancements #955 lists five items; this covers signing, encryption and manifests. Landing them separately from diffing/merging would be easier to review and revert.

What I'd suggest

Rebase onto current main yourself — you will resolve those 9 hunks faster and more reliably than I can, since you know which of your changes are load-bearing. If you want to make it land quickly, splitting the SHA-256 manifest work out as its own PR would very likely go in immediately: it is the least contentious piece and needs no key management at all.

Happy to review once it's rebased.

Conflicts were additive on both sides:
- CLI: combine --password/--verify-key with main's --yes/--context, and
  forward every Typer-defaulted option at each delegation site (the
  test_command_delegation_and_exit_codes meta-test enforces this).
- cgc_bundle: keep the _extract_bundle_archive refactor; its
  _extract_zip_safely applies the same component-wise Zip Slip check main
  added inline, to both the outer archive and the decrypted payload.
- _validate_bundle: run manifest and signature verification *and* main's
  identifier validation, rather than either alone.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>

@Shashankss1205 Shashankss1205 left a comment

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.

Verified the full round-trip end-to-end on a real bundle:

export --sign-key mysignkey --encrypt-password hunter2  → Signature: HMAC-SHA256, Encryption: AES-256-GCM
verify --password hunter2 --verify-key mysignkey        → Valid bundle
verify --password wrongpw                               → Failed to decrypt bundle payload
verify --verify-key badkey                              → Signature verification failed
import --password hunter2 --verify-key mysignkey        → imported, 33 nodes / 57 edges
import (no password)                                    → Bundle is encrypted; provide a password

Both negative cases fail correctly rather than silently degrading, which is the important part.

I resolved the conflicts with main and pushed to your branch. Three notes on how I resolved them, since they weren't purely mechanical:

  1. CLI options — combined your --password/--verify-key with main's newer --yes/--context rather than picking a side, and forwarded all four at every delegation site. test_command_delegation_and_exit_codes enforces this and caught one I'd missed at main.py:1254 (registry_download → bundle_import).
  2. Zip extraction — main had added inline Zip Slip protection while you refactored extraction into _extract_bundle_archive. I kept your refactor after checking that _extract_zip_safely does the equivalent component-wise check via relative_to(), and that it's applied to both the outer archive and the decrypted inner payload — so this is actually stronger than what it replaced, not weaker.
  3. _validate_bundle — both sides added a validation step (your manifest + signature checks, main's _validate_bundle_identifiers guarding against Cypher injection). Both now run in sequence.

Unit suite green (1166 passed). Merging — thanks, this is a solid addition to the .cgc format.

@Shashankss1205
Shashankss1205 merged commit f9b6e1b into CodeGraphContext:main Aug 13, 2026
11 of 15 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog tasks to Done in CGC Progress Board Aug 13, 2026
Shashankss1205 added a commit that referenced this pull request Aug 13, 2026
Two regressions from #1060, both caught by the integration suite:

1. bundle_export dereferences sign_key/encrypt_password. Called as a plain
   function rather than through Typer -- which tests/integration/test_parser_
   goldens.py:273 does -- an omitted option keeps its OptionInfo sentinel.
   That sentinel is truthy, so `if sign_key:` passed and sign_key.encode()
   raised AttributeError, failing all 20 golden tests. Normalized at the top
   of the command; these two are the only options here that get dereferenced.

2. The new bundle verify/inspect/diff subcommands were not reflected in the
   CLI inventory tests. verify/inspect/diff each require a .cgc positional
   argument, so they are excluded from the bare-invocation smoke matrix the
   same way bundle merge already is.

Full suites green: 1178 unit, 44 integration.

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
@Shashankss1205 Shashankss1205 added gssoc:approved GSSoC validation: counts toward scoring level:advanced GSSoC difficulty: 55 pts contributor / 30 mentor mentor:Shashankss1205 GSSoC mentor attribution: credits reviewing mentor quality:exceptional GSSoC quality: x1.5 contributor / +10 mentor type:security GSSoC type bonus: security labels Aug 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gssoc:approved GSSoC validation: counts toward scoring level:advanced GSSoC difficulty: 55 pts contributor / 30 mentor mentor:Shashankss1205 GSSoC mentor attribution: credits reviewing mentor quality:exceptional GSSoC quality: x1.5 contributor / +10 mentor type:security GSSoC type bonus: security

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

.cgc format advancements

3 participants