diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..b429dc4 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,11 @@ +# Hooks for the pre-commit framework - https://pre-commit.com +# +# This repo carries no native git hooks, so this is the route for a secret scan +# at commit time: install the framework once with `pre-commit install`, and the +# scan then runs on every commit. The hook is pinned to an exact gitleaks +# release tag. +repos: + - repo: https://github.com/gitleaks/gitleaks + rev: v8.30.1 + hooks: + - id: gitleaks diff --git a/docs/developer-guide/filter-pre-edit-hook.md b/docs/developer-guide/filter-pre-edit-hook.md index 274458e..e1bcac0 100644 --- a/docs/developer-guide/filter-pre-edit-hook.md +++ b/docs/developer-guide/filter-pre-edit-hook.md @@ -106,6 +106,11 @@ The hook below is registered in `MPE_TABLES.PRE_EDIT_HOOK` for a table with a da where %inc newfilt; run; + /* keep the order the editor first showed */ + proc sort data=work.out; + by &sortpk; + run; + /* hand the widened filter back to the editor */ data _null_; file filtref lrecl=32767; @@ -125,7 +130,7 @@ The hook below is registered in `MPE_TABLES.PRE_EDIT_HOOK` for a table with a da - **The user's clause.** `work.QUERY` is the filter's clauses as structured rows, and `%mp_filtergenerate` turns them back into a WHERE clause. This is the user's filter on its own, with no Row Level Security or validity clause mixed in. - **Data Controller's clause.** Calling `%mpe_filtermaster` with `filter_rk=-1` produces the part of the filter that is not the user's: the current-record validity clause and any Row Level Security, or `1=1` when there is neither. - **The combined filter.** The two clauses are combined as `( user OR previous-quarter ) AND ( validity + RLS )`, so the previous quarter is added to the user's selection without widening anything the user is not entitled to see. -- **The rows.** `work.OUT` is rebuilt with the combined filter, using the same drop list as the data step `getdata` runs itself - the transaction and processing columns, plus `&drop_rk`, the surrogate key that `getdata` hides when a table is registered with `RK_UNDERLYING`. On a bitemporal table `getdata` also deduplicates to the latest record per primary key (`by &pk &var_busfrom`); add that step too, or the re-read returns every temporal version rather than the current one. +- **The rows.** `work.OUT` is rebuilt with the combined filter, using the same drop list as the data step `getdata` runs itself - the transaction and processing columns, plus `&drop_rk`, the surrogate key that `getdata` hides when a table is registered with `RK_UNDERLYING` - and sorted on `&sortpk`, because `getdata` sorts before the hook runs and does not sort again afterwards. On a bitemporal table `getdata` also deduplicates to the latest record per primary key (`by &pk &var_busfrom`); add that step too, or the re-read returns every temporal version rather than the current one. - **The returned text.** `filtref` is overwritten with the combined filter, so the clause the editor shows is the one that was actually applied. ### What it looks like