Skip to content

Commit a8ac76c

Browse files
committed
a security policy, a PR template and a codelist version checker GitHub wf have been added
1 parent ea23c29 commit a8ac76c

6 files changed

Lines changed: 198 additions & 16 deletions

File tree

.github/SECURITY.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Security Policy
2+
3+
## Supported Versions
4+
5+
Only the latest stable release receives security patches.
6+
7+
## Reporting a Vulnerability
8+
9+
Please **do not** open a public GitHub issue for security vulnerabilities.
10+
11+
Use [GitHub's private vulnerability reporting](https://github.com/krose/entsoeapi/security/advisories/new) to report issues confidentially.
12+
13+
We aim to acknowledge reports within **7 days** and release a patch within **90 days**, depending on severity.
14+
15+
## Scope
16+
17+
In scope: - Leakage or improper handling of the `ENTSOE_PAT` API token - Unsafe processing of API responses (XML/JSON parsing) - Vulnerable transitive dependencies
18+
19+
Out of scope: - Vulnerabilities in the ENTSO-E API itself - Issues requiring a compromised R environment

.github/pull_request_template.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
## Description
2+
3+
<!-- What does this PR change and why? Link any related issues below. -->
4+
5+
Fixes #<!-- issue number, if applicable -->
6+
7+
## Type of change
8+
9+
- [ ] Bug fix
10+
- [ ] New endpoint / feature
11+
- [ ] Refactor / cleanup
12+
- [ ] Documentation only
13+
14+
## Affected module(s)
15+
16+
<!-- Tick all that apply -->
17+
- [ ] `en_market`
18+
- [ ] `en_load`
19+
- [ ] `en_generation`
20+
- [ ] `en_transmission`
21+
- [ ] `en_outages`
22+
- [ ] `en_balancing`
23+
- [ ] `en_helpers` / `utils`
24+
- [ ] Tests / CI
25+
- [ ] Documentation / vignettes
26+
27+
## Checklist
28+
29+
- [ ] Code follows project conventions (snake_case, `cli::` messages, `checkmate::` validation)
30+
- [ ] New exported functions include `@return` and `@examplesIf` roxygen tags
31+
- [ ] Tests added / updated — `covr::package_coverage()` passes at 100 %
32+
- [ ] `lintr::lint_package()` passes with no new warnings
33+
- [ ] `devtools::document()` run — man pages up-to-date
34+
- [ ] `devtools::check()` passes locally (0 errors, 0 warnings, 0 notes)
35+
- [ ] No `ENTSOE_PAT` tokens or secrets committed
36+
- [ ] `NEWS.md` updated (if user-facing change)
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# Workflow to check for ENTSO-E Code List version updates
2+
# Runs biweekly on Monday at 8:00 AM UTC
3+
on:
4+
schedule:
5+
- cron: "0 8 * * 1"
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: read
10+
issues: write
11+
12+
jobs:
13+
check-codelist-version:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- name: Get current week number
20+
id: week
21+
run: echo "week=$(date +%V)" >> $GITHUB_OUTPUT
22+
23+
- name: Check if biweek (only run on even weeks)
24+
run: |
25+
week=${{ steps.week.outputs.week }}
26+
if [ $((10#$week % 2)) -ne 0 ]; then
27+
echo "Skipping - odd week ($week)"
28+
exit 0
29+
fi
30+
echo "Running - even week ($week)"
31+
32+
- name: Fetch ENTSO-E Code List page
33+
id: fetch
34+
run: |
35+
response=$(curl -s "https://www.entsoe.eu/publications/electronic-data-interchange-edi-library/")
36+
37+
# Extract all version numbers and find the highest one
38+
version=$(echo "$response" | grep -oP 'Version\s+\K\d+' | sort -n | tail -1)
39+
40+
# Get the full line containing the highest version, then extract the date
41+
# Format: "* Mar 2, 2026 - Version 94 of the ENTSO-E Code list is published."
42+
line=$(echo "$response" | grep "Version $version " | head -1)
43+
date=$(echo "$line" | grep -oP '[A-Z][a-z]{2}\s+\d{1,2},\s+\d{4} | head -1')
44+
date=$(echo $date | head -1)
45+
46+
if [ -z "$version" ]; then
47+
echo "Failed to extract version number"
48+
exit 1
49+
fi
50+
51+
echo "version=$version" >> $GITHUB_OUTPUT
52+
echo "date=$date" >> $GITHUB_OUTPUT
53+
echo "Latest version: $version (published: $date)"
54+
55+
- name: Read stored version
56+
id: stored
57+
run: |
58+
if [ -f .github/CODELIST_VERSION ]; then
59+
stored_version=$(cat .github/CODELIST_VERSION)
60+
else
61+
stored_version="0"
62+
fi
63+
echo "stored_version=$stored_version" >> $GITHUB_OUTPUT
64+
echo "Stored version: $stored_version"
65+
66+
- name: Check existing issues for version
67+
id: check
68+
env:
69+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
70+
run: |
71+
version=${{ steps.fetch.outputs.version }}
72+
73+
# Search for existing issues about this version
74+
existing=$(gh issue list --state open --search "Code List Version $version" --json number --jq '.[0].number')
75+
76+
if [ -n "$existing" ]; then
77+
echo "Issue already exists: #$existing"
78+
echo "exists=true" >> $GITHUB_OUTPUT
79+
else
80+
echo "exists=false" >> $GITHUB_OUTPUT
81+
fi
82+
83+
- name: Create issue if new version found
84+
if: steps.check.outputs.exists == 'false'
85+
env:
86+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
87+
run: |
88+
version=${{ steps.fetch.outputs.version }}
89+
date=${{ steps.fetch.outputs.date }}
90+
stored_version=${{ steps.stored.outputs.stored_version }}
91+
92+
if [ "$version" -gt "$stored_version" ]; then
93+
gh issue create \
94+
--title "ENTSO-E Code List Version $version available" \
95+
--body "A new version of the ENTSO-E Code List has been published.
96+
97+
**Version:** $version
98+
**Published:** $date
99+
**Previous version:** $stored_version
100+
101+
**Action required:**
102+
- [ ] Review the changelog/release notes at ENTSO-E
103+
- [ ] Update package documentation if needed
104+
- [ ] Verify compatibility with current implementation
105+
106+
---
107+
*This issue was automatically created by the Code List version checker.*" \
108+
--label "enhancement"
109+
fi
110+
111+
- name: Update stored version
112+
if: steps.check.outputs.exists == 'false'
113+
run: |
114+
version=${{ steps.fetch.outputs.version }}
115+
echo "$version" > .github/CODELIST_VERSION
116+
117+
- name: Commit updated version file
118+
if: steps.check.outputs.exists == 'false'
119+
env:
120+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
121+
run: |
122+
git config user.name "github-actions[bot]"
123+
git config user.email "github-actions[bot]@users.noreply.github.com"
124+
git add .github/CODELIST_VERSION
125+
if ! git diff --staged --quiet; then
126+
git commit -m "Update Code List version to ${{ steps.fetch.outputs.version }}"
127+
git push
128+
else
129+
echo "No changes to commit"
130+
fi

README.Rmd

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,4 @@ entsoeapi::gen_per_prod_type(
193193

194194
## Code of Conduct
195195

196-
## Code of Conduct
197-
198196
Please note that the entsoeapi project is released with a [Contributor Code of Conduct](https://krose.github.io/entsoeapi/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms.

README.md

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ entsoeapi::load_actual_total(
507507
#> ── API call ────────────────────────────────────────────────────────────────────
508508
#> → https://web-api.tp.entsoe.eu/api?documentType=A65&processType=A16&outBiddingZone_Domain=10Y1001A1001A83F&periodStart=201912312300&periodEnd=202001012300&securityToken=<...>
509509
#> <- HTTP/2 200
510-
#> <- date: Tue, 07 Apr 2026 22:23:49 GMT
510+
#> <- date: Sun, 12 Apr 2026 12:21:59 GMT
511511
#> <- content-type: text/xml
512512
#> <- content-disposition: inline; filename="Actual Total Load_201912312300-202001012300.xml"
513513
#> <- x-content-type-options: nosniff
@@ -535,7 +535,7 @@ entsoeapi::load_actual_total(
535535
#> $ ts_object_aggregation_def <chr> "Area", "Area", "Area", "Area", "Area"…
536536
#> $ ts_business_type <chr> "A04", "A04", "A04", "A04", "A04", "A0…
537537
#> $ ts_business_type_def <chr> "Consumption", "Consumption", "Consump…
538-
#> $ created_date_time <dttm> 2026-04-07 22:23:49, 2026-04-07 22:23
538+
#> $ created_date_time <dttm> 2026-04-12 12:21:59, 2026-04-12 12:21
539539
#> $ revision_number <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
540540
#> $ time_period_time_interval_start <dttm> 2019-12-31 23:00:00, 2019-12-31 23:00…
541541
#> $ time_period_time_interval_end <dttm> 2020-01-01 23:00:00, 2020-01-01 23:00…
@@ -565,7 +565,7 @@ entsoeapi::gen_per_prod_type(
565565
#> ── API call ────────────────────────────────────────────────────────────────────
566566
#> → https://web-api.tp.entsoe.eu/api?documentType=A75&processType=A16&in_Domain=10Y1001A1001A83F&periodStart=201912312300&periodEnd=202001012300&securityToken=<...>
567567
#> <- HTTP/2 200
568-
#> <- date: Tue, 07 Apr 2026 22:23:49 GMT
568+
#> <- date: Sun, 12 Apr 2026 12:22:04 GMT
569569
#> <- content-type: text/xml
570570
#> <- content-disposition: inline; filename="Aggregated Generation per Type_201912312300-202001012300.xml"
571571
#> <- x-content-type-options: nosniff
@@ -580,10 +580,10 @@ entsoeapi::gen_per_prod_type(
580580
#> ✔ Additional definitions have been added!
581581
#> Rows: 1,632
582582
#> Columns: 25
583-
#> $ ts_in_bidding_zone_domain_mrid <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA
584-
#> $ ts_in_bidding_zone_domain_name <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA
585-
#> $ ts_out_bidding_zone_domain_mrid <chr> "10Y1001A1001A83F", "10Y1001A1001A83F"
586-
#> $ ts_out_bidding_zone_domain_name <chr> "Germany", "Germany", "Germany", "Germ
583+
#> $ ts_in_bidding_zone_domain_mrid <chr> "10Y1001A1001A83F", "10Y1001A1001A83F"
584+
#> $ ts_in_bidding_zone_domain_name <chr> "Germany", "Germany", "Germany", "Germ
585+
#> $ ts_out_bidding_zone_domain_mrid <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA
586+
#> $ ts_out_bidding_zone_domain_name <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA
587587
#> $ type <chr> "A75", "A75", "A75", "A75", "A75", "A7…
588588
#> $ type_def <chr> "Actual generation per type", "Actual …
589589
#> $ process_type <chr> "A16", "A16", "A16", "A16", "A16", "A1…
@@ -592,9 +592,9 @@ entsoeapi::gen_per_prod_type(
592592
#> $ ts_object_aggregation_def <chr> "Resource type", "Resource type", "Res…
593593
#> $ ts_business_type <chr> "A01", "A01", "A01", "A01", "A01", "A0…
594594
#> $ ts_business_type_def <chr> "Production", "Production", "Productio…
595-
#> $ ts_mkt_psr_type <chr> "B10", "B10", "B10", "B10", "B10", "B1
596-
#> $ ts_mkt_psr_type_def <chr> "Hydro-electric pure pumped storage he
597-
#> $ created_date_time <dttm> 2026-04-07 22:23:49, 2026-04-07 22:23
595+
#> $ ts_mkt_psr_type <chr> "B01", "B01", "B01", "B01", "B01", "B0
596+
#> $ ts_mkt_psr_type_def <chr> "Biomass", "Biomass", "Biomass", "Biom
597+
#> $ created_date_time <dttm> 2026-04-12 12:22:04, 2026-04-12 12:22
598598
#> $ revision_number <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
599599
#> $ time_period_time_interval_start <dttm> 2019-12-31 23:00:00, 2019-12-31 23:00…
600600
#> $ time_period_time_interval_end <dttm> 2020-01-01 23:00:00, 2020-01-01 23:00…
@@ -603,14 +603,12 @@ entsoeapi::gen_per_prod_type(
603603
#> $ ts_time_interval_end <dttm> 2020-01-01 23:00:00, 2020-01-01 23:00…
604604
#> $ ts_mrid <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
605605
#> $ ts_point_dt_start <dttm> 2019-12-31 23:00:00, 2019-12-31 23:15…
606-
#> $ ts_point_quantity <dbl> 194.92, 225.11, 286.19, 397.02, 284.99
606+
#> $ ts_point_quantity <dbl> 4809.13, 4803.04, 4787.15, 4787.26, 47
607607
#> $ ts_quantity_measure_unit_name <chr> "MAW", "MAW", "MAW", "MAW", "MAW", "MA…
608608
```
609609

610610
## Code of Conduct
611611

612-
## Code of Conduct
613-
614612
Please note that the entsoeapi project is released with a [Contributor
615613
Code of
616614
Conduct](https://krose.github.io/entsoeapi/CODE_OF_CONDUCT.html). By

RELEASE_CHECKLIST.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424

2525
- [ ] Run `devtools::run_examples(fresh = TRUE)` — all examples pass, no unexpected errors
2626
- [ ] Run `devtools::test()` — all tests pass, no unexpected skips
27-
- [ ] `devtools::test_coverage()` — no significant test coverage regression
27+
- [ ] Run `devtools::test_coverage()` — no significant test coverage regression
28+
- [ ] Run `semgrep ci` in CLI — to check security vulnerabilities
2829

2930
## 4. R CMD CHECK
3031

0 commit comments

Comments
 (0)