Skip to content

PyPi and security fix - #799

Merged
Hananel-Hazan merged 16 commits into
masterfrom
hananel
Sep 16, 2026
Merged

Hananel-Hazan merged 16 commits into
masterfrom
hananel

Conversation

@Hananel-Hazan

Copy link
Copy Markdown
Collaborator

No description provided.

Hananel-Hazan and others added 16 commits September 2, 2026 18:30
… constants, in-place neuron state; fix network.to() on MulticompartmentConnection

- PostPre/Hebbian (classic + MCC) apply the outer-product update with one addmm_
- LearningRule.update skips the w *= 1.0 multiply when no weight decay is set
- Local-connection rules scale rows instead of bmm with torch.eye per step
- MSTDP/MSTDPET cache exp(-dt/tc) and default a_plus/a_minus tensors
- Nodes update v/refrac_count/theta/x in place (same ops, same order)
- rank_order encoding vectorised
- Fix AbstractMulticompartmentConnection._apply(recurse) so network.to(device)
  works on DiehlAndCook2015
- test/network/test_perf_equivalence.py pins each change to its reference formula
- examples/benchmark/hot_path_bench.py; CLAUDE.md + .vscode point at the bindsNET env

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- test/network/test_learning_rule_specs.py: PostPre / WeightDependentPostPre /
  Hebbian vs Morrison, Diesmann & Gerstner (2008) eqs 11-14; Rmax vs Vasilaki
  et al. (2009) eqs 7, 8, 13; MCC PostPre/Hebbian vs classic; Diehl & Cook
  deviation pinned
- test_mstdp_florian.py: Florian (2007) equation numbers recorded
- Fix reversed Rmax tc_c docstring and misleading MSTDP/MSTDPET zero_lag comments
- docs/source/models_spec.rst: cite the equations per rule
- CHANGELOG entry

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ources

- Nodes.forward applies Network.run's clamp/unclamp before the trace update
  (previously applied after, so forced spikes never reached the traces the
  learning rules read; affected supervised_mnist.py)
- Tests: TestClampEntersTraces; STDP window test now also driven by clamp
- README section 'Learning rules and their sources'; models_spec.rst clamp and
  known-deviations sections; CLAUDE.md rule/validation notes; CHANGELOG

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…re, move rule docs

- bindsnet.learning.DiehlAndCook + MCC_learning.DiehlAndCook: post-spike-only
  dw = eta (x_pre - x_tar)(w_max - w)^mu (Diehl & Cook 2015 Sect. 2.3);
  DiehlAndCook2015(learning_rule=..., learning_rule_kwargs=...) opt-in, default
  PostPre unchanged
- MCC_learning.PostPre no longer scales updates by dt (per-spike increment, as
  the classic rule and Morrison 2008 eqs 13-14)
- Weight feature forwards extra kwargs to its learning rule
- Tests: DiehlAndCook vs paper reference (mu, x_tar, both trace modes), MCC
  vs classic at dt 1.0 and 0.5, dt-independence of MCC PostPre, model opt-in
- Docs: bindsnet/learning/README.md (moved from top-level README), models_spec,
  CLAUDE.md, CHANGELOG

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Follow-up to #794. MSTDP creates p_plus and p_minus lazily on the first
update, because only then are the batch size and device known. #794 made
reset_state_variables zero them unconditionally, so calling
network.reset_state_variables() before the first run raised
AttributeError: 'MSTDP' object has no attribute 'p_plus'. Building a
network and resetting it before the first episode is a normal thing to
do, so this was reachable.

Declare p_plus and p_minus as None in __init__ alongside the other lazily
built state, switch the update path's hasattr guards to 'is None' to
match, and have the reset skip whatever has not been built.

MSTDPET was never affected: it builds both in __init__.

New test parametrised over MSTDP, MSTDPET and PostPre resets a freshly
built network before running it. It fails for MSTDP without this change.
Full suite 94 passed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Brings in the six commits master gained today: four dependency bumps, the
removal of the dead AbstractFeature.degrade hook (#793), the learning-rule
reset fix (#794), and its follow-up for MSTDP's lazily built state (#795).

No textual conflicts. The two files both sides touched, MCC_learning.py and
topology_features.py, merged cleanly and the result is correct in both
directions: this branch's perf work (the MSTDP fast path, the fold cache,
the cached decay tensors) is intact, and master's reset fix reaches the
learning rules through the feature chain as intended.

Full suite on the merge: 182 passed, which includes this branch's
test_perf_equivalence.py and test_learning_rule_specs.py alongside
master's new reset tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
DiehlAndCook arrived on this branch while the reset audit (#794) was
happening on master, so it kept the bare 'return' that the audit removed
everywhere else.

It holds no state between steps: each update comes from the source trace,
the target spikes and the current weight, exactly like Hebbian. So the
no-op is correct, but it now says so rather than looking like the
oversight the other rules turned out to be.

Extends the two reset tests to cover Hebbian and DiehlAndCook as well.
Full suite 186 passed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Master re-merged after #795 landed there as a squashed commit (7d2a66e).
This branch already carried the same fix as the unsquashed f2d61ce, so git
had two identities for one change and flagged the one place their text
differs.

Single conflict, in the parametrise list of
test_reset_before_first_run_does_not_raise. Kept this branch's version,
covering five rules including Hebbian and DiehlAndCook; master's covered
three. DiehlAndCook exists only on this branch and the wider list is a
superset, so it is the correct side.

The resolved tree is identical to this branch's previous HEAD, so this
joins the two histories without changing content. Recording it stops the
same conflict recurring on every future merge from master.

Full suite 186 passed, including all ten parametrised reset cases.
black --check clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CodeQL alerts 10, 11 and 12 (actions/missing-workflow-permissions) flag that
none of the three workflows declare a permissions block, so each run inherits
the repository default token scope.

None of the three write back to the repository: black.yml runs psf/black,
python-app.yml runs flake8 and pytest, pythonpackage.yml runs black and pytest
across Python 3.11-3.13. Read-only access to the repository contents is
sufficient for all of them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… sites

bindsnet.network.load() reads a Python pickle file via torch.load, so loading a
network file from an untrusted source runs code in that file. This is standard
torch.load behaviour across the PyTorch ecosystem rather than a defect specific
to BindsNET, and it is not being treated as a vulnerability, but it was
completely undocumented. Adds a warning to each affected function's docstring
and a "Loading saved networks and models" section to SECURITY.md.

load() gains a weights_only parameter passed through to torch.load. It defaults
to False, so behaviour is unchanged: Network.save() stores the whole network
object rather than a tensor state dict, and the safe loader cannot read those
files at all. Reversing the default would break every saved network.

Reviewing the neighbouring call sites turned up three things that were simply
broken, all from PyTorch 2.6 flipping the weights_only default to True:

- Network.clone() raised UnpicklingError. No test, no caller in the tree.
- Network.save() called add_safe_globals([self]) with an instance where a class
  is expected. It did nothing useful and corrupted PyTorch's safe-globals
  registry, so any later load in the same process failed with
  'Network' object has no attribute '__qualname__'. Removed.
- conversion.ann_to_snn and data_based_normalization raised UnpicklingError when
  given a path instead of a module. Only the in-memory form was tested.

SpokenMNIST now reads its processed-data cache with weights_only=True. That
cache holds only tensors, so refusing code execution there costs nothing. It is
the one place the reporter's suggested fix actually applies.

Six regression tests added, each carrying the reason in its docstring. No
per-timestep path is touched, so performance is unaffected. Full suite: 193
passed.

Reported-by: Gavin Branaa <gbranaa4@gmail.com>
Thanks to Gavin for the careful private report, and for the follow-up that led
to the three fixes above.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Add a trusted-publishing workflow (runs on GitHub Release or by hand),
drop install requirements nothing imports (Cython, scikit-build, foolbox,
numba), loosen torch/torchvision to >=2.14,<3 / >=0.29,<1, point README
and install docs at pip install bindsnet, and record in CHANGELOG that
PyPI 0.3.4 is master on 2026-09-16, not the 0.3.4 tag.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…data, working Dockerfile

- test_perf_equivalence: batch-1 fused addmm_ checks accept float32 rounding
  (bit equality is CPU dependent; 5 tests failed on GitHub runners) and warn
  with the size of the difference.
- Poetry 2.4.3 in CI and docs; metadata moved to [project]; lock resolves to
  the same packages; poetry-core>=2.0; unused setup.py removed.
- Dockerfile rewritten (old base image, installer and .python-version gone).
- publish.yml uses download-artifact v8; old repo links fixed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Hananel-Hazan
Hananel-Hazan merged commit d611de9 into master Sep 16, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant