Skip to content

fix: mf_getvalue edge case - #459

Merged
tmoody merged 10 commits into
mainfrom
fix/mf_getvalue_edgecase
Oct 13, 2026
Merged

tmoody merged 10 commits into
mainfrom
fix/mf_getvalue_edgecase

Conversation

@tmoody

@tmoody tmoody commented Oct 13, 2026 •

Copy link
Copy Markdown
Member

Issue

base macro mf_getvalue can accidentally return a value in error when a populated global macro variable exists with an identical name to the variable name being requested from input data that yields no eligible row to perform fetchobs() upon.

Code:

data sample;
  key = 0;
  VarA = "xyz";
run;

%let VarA = "abc";

%let stored_val = %mf_getvalue(sample,VarA,filter=(key > 0));

%put NOTE: &=VarA;

Log:

80     data sample;
81       key = 0;
82       VarA = "xyz";
83     run;
NOTE: The data set WORK.SAMPLE has 1 observations and 2 variables.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds
      
84     
85     %let VarA = "abc";
86     
87     %let stored_val = %mf_getvalue(sample,VarA,filter=(key > 0));
WARNING: End of file.
88     
89     %put NOTE: &=stored_val;
NOTE: STORED_VAL="abc"

Intent

Rejig the current column extraction method which turns all variables in the data vector into equivalent macro variables.

Implementation

Replace %syscall set( )-based method with explicit query for the requested column.

Checks

  • Code is formatted correctly (sasjs lint).
  • Any new functionality has been unit tested.
  • All unit tests are passing (sasjs test) (see below).
  • The PR desc or underlying commits follow the Conventional Commit standard
image

@tmoody tmoody self-assigned this Oct 13, 2026

@sasjs-dev sasjs-dev Bot 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.

Reviewed the full base...head diff at 377d03d (base/mf_getvalue.sas, generated all.sas, tests/base/mf_getvalue.test.sas) plus repo hardening state. The %syscall set -> explicit getvarN/getvarC rework fixes the global-macro-variable collision correctly, all.sas is in sync with the source macro, and the new Test 9 covers the regression. Findings:

  • base/mf_getvalue.sas:60-66 - behavior change worth confirming before merge: values previously flowed through %syscall set(dsid) (CALL SET), which applies the variable's assigned format when populating the macro value; %sysfunc(getvarn()) returns the raw numeric. For a numeric column with e.g. date9. attached, the returned value changes from the formatted string to the underlying SAS date number. If any caller relies on the formatted representation this is a silent breaking change - either preserve the format (read it via varfmt() and wrap with putc()) or state the change explicitly in the PR description.

  • CI: the SAS test suite has not executed on any commit of this PR. The Node.js CI run at 76a7c15 failed in the "Start Open VPN 3" step (VPN infra, all build/test steps skipped), and the run at the current head 377d03d sits at action_required awaiting workflow approval (triggered by the all.sas automation commit). Request approval or rerun so the new getvarN/getvarC path is exercised by the full suite in CI, not only locally.

  • .npmrc - has ignore-scripts=true but is missing save-exact=true; add it so local installs cannot reintroduce ^/~ ranges.

  • No npm audit step in any workflow (.github/workflows/run-tests.yml, main.yml, notmain.yml). The Snyk PR check scans dependencies, but the pipeline itself has no audit gate that fails the build - add npm audit (default level) as a failing step.

  • .git-hooks/pre-commit ships a pinned gitleaks staged scan, but since the install-time prepare script was dropped nothing wires it up (no git config core.hooksPath ./.git-hooks step and no docs mention it), so a fresh clone activates no hooks and the secret scan is dormant. Wire the hooksPath into setup/docs or CI, or move to a .pre-commit-config.yaml gitleaks hook.

5 findings above for review.

sasjs-dev Bot and others added 3 commits October 13, 2026 13:50
Addresses the review findings on repo hardening:

- .npmrc: add save-exact so local installs cannot reintroduce ^/~ ranges
- run-tests.yml: scan for secrets with the pinned gitleaks binary and run
  npm audit as a failing step
- main.yml: run npm audit before release
- CONTRIBUTING.md: document `git config core.hooksPath ./.git-hooks`; the
  hooks are inert until that is set, so a fresh clone commits unscanned
Two changes so the review findings are observable in CI:

- run-tests.yml: move npm ci, the gitleaks scan, npm audit and lint ahead
  of the VPN steps, so they report even when the tunnel is down. The SAS
  suite is currently blocked by the VPN step timing out, which skips every
  later step.
- notmain.yml: drop --allow-empty so an unchanged all.sas produces no
  commit. The empty bot commit made the PR head a run that needs manual
  approval, which is what kept the SAS suite from executing on the head.
@sasjs-dev

sasjs-dev Bot commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

Follow-up on the five review findings (head 271251c).

Format behaviour change (base/mf_getvalue.sas:60-66) - acknowledged, not addressed in this PR. The getvarN/getvarC value handling stays as submitted here; the formatted-vs-raw question is left for a separate change.

CI - the SAS test suite - approved the pending run and reran it. It fails at Start Open VPN 3: the session is created but never connects, the 1-minute step timeout fires, and every later step is skipped. This is not specific to this PR - every run-tests run back to 2026-09-15 fails the same way, so the SAS suite has not executed in CI on any commit for a month. There is no open issue tracking it.

Two CI-side fixes landed in this PR so the findings are observable:

  • run-tests.yml now runs npm ci, the gitleaks scan, npm audit and lint before the VPN steps, so the static gates report even when the tunnel is down. Latest run 38409132304: steps 4-7 all green, the failure isolated to step 11 (VPN).
  • notmain.yml no longer commits with --allow-empty. It was creating an empty chore: updating all.sas commit on every push, which made the PR head a run that needs manual approval - the reason the suite kept not executing on the head. The head now stays on the pushed commit and the PR run executes without approval.

The SAS suite itself still needs the tunnel to come up. That is infrastructure, not this repo.

.npmrc - save-exact=true added.

npm audit - added as a failing step to run-tests.yml and main.yml, the PR and release gates. Deliberately not added to notmain.yml: that workflow exists to keep all.sas in sync, and a new advisory should not block it.

.git-hooks - git config core.hooksPath ./.git-hooks is now documented in .github/CONTRIBUTING.md, and CI runs the same pinned gitleaks binary as a backstop, so the secret scan is enforced even in a clone with no hooks wired up.

@sasjs-dev sasjs-dev Bot 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.

Re-review at 271251c, superseding the review at 377d03d. Scope: the delta since the prior review (the CI/hardening commits bd56671 and 271251c, .npmrc, CONTRIBUTING.md) plus the unchanged mf_getvalue change at the new head; verified all.sas is in sync with base/mf_getvalue.sas and the squash subject ("fix: mf_getvalue edge case") is a release-driving conventional commit.

  • .github/workflows/run-tests.yml:70 - the pipeline is red at this head: the test job fails at "Start Open VPN 3" (the 1-minute timeout fires; the session is created but never connects) and every step after it is skipped, so "Run all tests" at run-tests.yml:119 never executes and the new getvarN/getvarC path is unexercised in CI. The static gates moved ahead of the VPN all pass, and the failure is pre-existing infrastructure - every run-tests run back to 2026-09-15 fails identically - so it is not introduced by this PR's code. Decide at merge: accept the local sasjs test evidence in the PR description, or hold until the tunnel is fixed so the suite covers the new code path.

  • base/mf_getvalue.sas:60-66 - the format behavior change from the prior review is still in the diff: the old CALL SET path applied the variable's assigned format when materializing the macro value, while %sysfunc(getvarN()) returns the raw numeric, so a numeric column with e.g. date9. attached now returns the underlying SAS date number instead of the formatted string. Deferred to a separate change per the thread; restated here so the record at this head carries it as a known, intentional behavior change.

2 findings above for review.

@tmoody
tmoody merged commit 413c7d8 into main Oct 13, 2026
3 of 4 checks passed
@tmoody
tmoody deleted the fix/mf_getvalue_edgecase branch October 13, 2026 17:28
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 5.3.2 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants