Skip to content

Commit f23e9da

Browse files
authored
restrict plugin-manager endpoint to localhost and station domain and update e2e tests (#1436)
* restrict plugin-manager endpoint to localhost and station domain and update e2e tests * fix robot tests * fix copilot review and upgrade deprecated macos-13 to macos-15 in pipelines * remove old CI delete and install wallet plugin process * fix ubuntu deb packaging process * update fyne.io/fyne/v2 from v2.3.4 to v2.7.1~ to have compatibility with fyne.io/tools/cmd/fyne@latest. * test * test * test * test * test * fix macos pipeline issue
1 parent 17be025 commit f23e9da

File tree

17 files changed

+313
-701
lines changed

17 files changed

+313
-701
lines changed

.github/workflows/build.yml

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ jobs:
2525
- os: ubuntu-24.04
2626
arch: amd64
2727
target: linux
28-
- os: macos-13
28+
- os: macos-15
2929
arch: amd64
3030
target: darwin
31-
- os: macos-13
31+
- os: macos-15
3232
arch: arm64
3333
target: darwin
3434

@@ -61,7 +61,7 @@ jobs:
6161
if: matrix.target != 'windows'
6262
shell: bash
6363
run: |
64-
task package
64+
task package OS=${{ matrix.target }}
6565
- name: Rename binary for ${{ matrix.target }} on ${{ matrix.arch }}
6666
shell: bash
6767
run: |
@@ -75,15 +75,27 @@ jobs:
7575
massastation_${{ matrix.target }}_${{ matrix.arch }}.exe
7676
if-no-files-found: error
7777
retention-days: 7
78-
- name: Upload Package
79-
# We don't need to upload package for windows since we do not package for windows.
80-
if: matrix.target != 'windows'
78+
- name: Prepare macOS app bundle for upload
79+
if: matrix.target == 'darwin'
80+
shell: bash
81+
# The actions/upload-artifact only import content of a folder, so we need to create a temporary folder to upload MassaStation.app
82+
run: |
83+
mkdir -p package_output
84+
cp -R MassaStation.app package_output/
85+
- name: Upload Package (macOS)
86+
if: matrix.target == 'darwin'
8187
uses: actions/upload-artifact@v4
8288
with:
8389
name: massastation_${{ matrix.target }}_${{ matrix.arch }}_package
84-
path: |
85-
MassaStation.app
86-
MassaStation.tar.xz
90+
path: package_output/
91+
if-no-files-found: error
92+
retention-days: 1
93+
- name: Upload Package (Linux)
94+
if: matrix.target == 'linux'
95+
uses: actions/upload-artifact@v4
96+
with:
97+
name: massastation_${{ matrix.target }}_${{ matrix.arch }}_package
98+
path: MassaStation.tar.xz
8799
if-no-files-found: error
88100
retention-days: 1
89101

@@ -97,7 +109,7 @@ jobs:
97109
matrix:
98110
arch: [amd64, arm64]
99111

100-
runs-on: macos-13
112+
runs-on: macos-15
101113
steps:
102114
- name: Checkout repository
103115
uses: actions/checkout@v4

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jobs:
77
runs-on: ${{ matrix.os }}
88
strategy:
99
matrix:
10-
os: ["windows-latest", "ubuntu-latest", "macos-13"]
10+
os: ["windows-latest", "ubuntu-latest", "macos-15"]
1111
steps:
1212
- uses: actions/checkout@v4
1313
- name: installing dependencies

Taskfile.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ tasks:
1919
- cmd: go install github.com/go-swagger/go-swagger/cmd/swagger@latest
2020
- cmd: go install golang.org/x/tools/cmd/stringer@latest
2121
- cmd: go install go.uber.org/mock/mockgen@v0.2.0
22-
- cmd: go install fyne.io/fyne/v2/cmd/fyne@latest
22+
- cmd: go install fyne.io/tools/cmd/fyne@latest
2323

2424
install-dev:
2525
desc: Installs development dependencies (fmt, lint, etc.)
@@ -102,7 +102,7 @@ tasks:
102102
desc: Packages MassaStation using fyne
103103
platforms: [linux, darwin]
104104
cmds:
105-
- cmd: fyne package -name MassaStation -icon ./int/systray/embedded/logo.png -appID net.massalabs.massastation -exe massastation
105+
- cmd: fyne package -name MassaStation -icon ../../int/systray/embedded/logo.png --app-id net.massalabs.massastation -src ./cmd/massastation {{if .OS}}--os {{.OS}}{{end}}
106106

107107
generate-dirs:
108108
desc: Generates required directories for MassaStation

api/domain_restriction.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func DomainRestrictionMiddleware(handler http.Handler) http.Handler {
2929
}
3030

3131
func IsRestrictedPath(path string) bool {
32-
restrictedPaths := []string{"/network"}
32+
restrictedPaths := []string{"/network", "/plugin-manager"}
3333
for _, restrictedPath := range restrictedPaths {
3434
if strings.HasPrefix(path, restrictedPath) {
3535
return true

api/test/robot_tests/cmd/keywords.resource

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,42 +7,42 @@ Resource ../keywords.resource
77
Resource ../variables.resource
88

99
*** Variables ***
10-
${WALLET_PLUGIN_VERSION} v0.5.0
10+
${WALLET_PLUGIN_VERSION} v0.5.6
1111

1212
*** Keywords ***
1313
Suite Setup
1414
Basic Suite Setup
1515
Switch To Buildnet
1616
Init SC build environment
17-
${GITHUB_ACTIONS} Get Environment Variable GITHUB_ACTIONS false
18-
IF "${GITHUB_ACTIONS}" == "true"
19-
Log To Console We are in the CI
20-
Delete Wallet Plugin
21-
Install Wallet Plugin
22-
END
17+
Install Wallet Plugin
2318

2419
Delete Wallet Plugin
25-
Log To Console Deleting Massa Wallet Plugin
20+
Log To Console Attempt to delete Massa Wallet Plugin if exist
2621
${pluginId}= Get Plugin ID From Author and Name massalabs wallet
2722
IF "${pluginId}" != "${EMPTY}"
28-
Log To Console Deleting plugin with ID ${pluginId}
29-
${response}= DELETE ${API_URL}/plugin-manager/${pluginId}
23+
Log To Console Deleting plugin Massa Wallet with ID ${pluginId}
24+
${headers}= Create Dictionary Origin=http://localhost
25+
${response}= DELETE ${API_URL}/plugin-manager/${pluginId} headers=${headers}
3026
Sleep 1 seconds # Wait for the plugin to be deleted
3127
END
3228

3329
Install Wallet Plugin
34-
Log To Console Installing Massa Wallet Plugin
35-
${source}= Set Variable
36-
... https://massa-station-assets.s3.eu-west-3.amazonaws.com/plugins/wallet/${WALLET_PLUGIN_VERSION}/wallet-plugin_${OS}-${ARCH}.zip
37-
${response}= POST
38-
... ${API_URL}/plugin-manager
39-
... params=source=${source}
40-
... expected_status=${STATUS_NO_CONTENT}
41-
Sleep 1 seconds # Wait for the plugin to be registered
30+
Log To Console Attempt to install Massa Wallet Plugin if not already installed
31+
${pluginId}= Get Plugin ID From Author and Name massalabs wallet
32+
IF "${pluginId}" == "${EMPTY}"
33+
Log To Console Installing Massa Wallet Plugin because it does not exist yet
34+
${source}= Set Variable
35+
... https://massa-station-assets.s3.eu-west-3.amazonaws.com/plugins/wallet/${WALLET_PLUGIN_VERSION}/wallet-plugin_${OS}-${ARCH}.zip
36+
${headers}= Create Dictionary Origin=http://localhost
37+
${response}= POST
38+
... ${API_URL}/plugin-manager
39+
... params=source=${source}
40+
... headers=${headers}
41+
... expected_status=${STATUS_NO_CONTENT}
42+
Sleep 1 seconds # Wait for the plugin to be registered
43+
END
4244

4345
Init SC build environment
4446
Log To Console Initializing SC build environment
45-
Log To Console Installing SC dependencies
4647
Run cd testSC; npm install
47-
Log To Console Building SC
4848
Run cd testSC; npm run build

api/test/robot_tests/plugin_manager/keywords.resource

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ Delete all plugins
1616
Log To Console Deleting all plugins
1717
${response}= GET ${API_URL}/plugin-manager
1818
FOR ${element} IN @{response.json()}
19-
${response}= DELETE ${API_URL}/plugin-manager/${element['id']}
19+
${headers}= Create Dictionary Origin=http://localhost
20+
${response}= DELETE ${API_URL}/plugin-manager/${element['id']} headers=${headers}
2021
Status Should Be ${STATUS_NO_CONTENT}
2122
END
2223

@@ -25,5 +26,6 @@ Delete Hello World Plugin
2526
Log To Console Deleting Hello World Plugin
2627
${pluginId}= Get Plugin ID From Author and Name massalabs hello-world
2728
IF "${pluginId}" != "${EMPTY}"
28-
${response}= DELETE ${API_URL}/plugin-manager/${pluginId}
29+
${headers}= Create Dictionary Origin=http://localhost
30+
${response}= DELETE ${API_URL}/plugin-manager/${pluginId} headers=${headers}
2931
END

api/test/robot_tests/plugin_manager/plugin_manager.robot

Lines changed: 97 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,9 @@ Resource variables.resource
88
Resource ../variables.resource
99

1010
Suite Setup Suite Setup
11-
Suite Teardown Delete all plugins
1211

1312
*** Variables ***
14-
${HELLO_WORLD_PLUGIN_VERSION} v0.0.8
13+
${HELLO_WORLD_PLUGIN_VERSION} v0.0.11
1514

1615
*** Test Cases ***
1716
GET /plugin-manager with no plugins
@@ -23,12 +22,33 @@ GET /plugin-manager with no plugins
2322
POST /plugin-manager?source={{pluginSource}}
2423
${source}= Set Variable
2524
... https://github.com/massalabs/station-massa-hello-world/releases/download/${HELLO_WORLD_PLUGIN_VERSION}/station-massa-hello-world_${OS}-${ARCH}.zip
25+
${headers}= Create Dictionary Origin=http://localhost
2626
${response}= POST
2727
... ${API_URL}/plugin-manager
2828
... params=source=${source}
29+
... headers=${headers}
2930
... expected_status=${STATUS_NO_CONTENT}
3031
Sleep 1 seconds # Wait for the plugin to be registered
3132

33+
POST /plugin-manager?source={{pluginSource}} should fail when Origin not provided
34+
${source}= Set Variable
35+
... https://github.com/massalabs/station-massa-hello-world/releases/download/${HELLO_WORLD_PLUGIN_VERSION}/station-massa-hello-world_${OS}-${ARCH}.zip
36+
${response}= POST
37+
... ${API_URL}/plugin-manager
38+
... params=source=${source}
39+
... expected_status=${STATUS_FORBIDDEN}
40+
41+
POST /plugin-manager?source={{pluginSource}} should fail when Origin not allowed
42+
${source}= Set Variable
43+
... https://github.com/massalabs/station-massa-hello-world/releases/download/${HELLO_WORLD_PLUGIN_VERSION}/station-massa-hello-world_${OS}-${ARCH}.zip
44+
${headers}= Create Dictionary Origin=http://malicious.example.com
45+
${response}= POST
46+
... ${API_URL}/plugin-manager
47+
... params=source=${source}
48+
... headers=${headers}
49+
... expected_status=${STATUS_FORBIDDEN}
50+
51+
3252
GET /plugin-manager with one plugin
3353
${response}= GET ${API_URL}/plugin-manager
3454
Status Should Be ${STATUS_OK}
@@ -45,25 +65,54 @@ GET /plugin-manager/{id}
4565
POST /plugin-manager/{id}/execute with stop command
4666
${id}= Get Plugin ID From Author and Name massa-labs hello-world
4767
${data}= Create Dictionary command=stop
68+
${headers}= Create Dictionary Origin=http://localhost
4869
${response}= POST
4970
... ${API_URL}/plugin-manager/${id}/execute
71+
... headers=${headers}
5072
... expected_status=${STATUS_NO_CONTENT}
5173
... json=${data}
5274

75+
POST /plugin-manager/{id}/execute should fail when Origin not allowed
76+
${id}= Get Plugin ID From Author and Name massa-labs hello-world
77+
${data}= Create Dictionary command=stop
78+
${headers}= Create Dictionary Origin=http://malicious.example.com
79+
${response}= POST
80+
... ${API_URL}/plugin-manager/${id}/execute
81+
... headers=${headers}
82+
... expected_status=${STATUS_FORBIDDEN}
83+
... json=${data}
84+
${data}= Create Dictionary command=start
85+
${response}= POST
86+
... ${API_URL}/plugin-manager/${id}/execute
87+
... headers=${headers}
88+
... expected_status=${STATUS_FORBIDDEN}
89+
... json=${data}
90+
${data}= Create Dictionary command=restart
91+
${response}= POST
92+
... ${API_URL}/plugin-manager/${id}/execute
93+
... headers=${headers}
94+
... expected_status=${STATUS_FORBIDDEN}
95+
... json=${data}
96+
97+
5398
POST /plugin-manager/{id}/execute with start command
5499
${id}= Get Plugin ID From Author and Name massa-labs hello-world
55100
${data}= Create Dictionary command=start
101+
${headers}= Create Dictionary Origin=http://localhost
56102
${response}= POST
57103
... ${API_URL}/plugin-manager/${id}/execute
104+
... headers=${headers}
58105
... expected_status=${STATUS_NO_CONTENT}
59106
... json=${data}
60107
Sleep 1 seconds # Wait for the plugin to be started
61108

62109
POST /plugin-manager/{id}/execute with restart command
63110
${id}= Get Plugin ID From Author and Name massa-labs hello-world
64111
${data}= Create Dictionary command=restart
112+
${headers}= Create Dictionary Origin=http://localhost
65113
${response}= POST
66114
... ${API_URL}/plugin-manager/${id}/execute
115+
... headers=${headers}
67116
... expected_status=${STATUS_NO_CONTENT}
68117
... json=${data}
69118
Sleep 1 seconds # Wait for the plugin to be restarted
@@ -100,8 +149,10 @@ GET /plugin/{author}/{name}/
100149
POST /plugins-manager/{id}/execute already started
101150
${id}= Get Plugin ID From Author and Name massa-labs hello-world
102151
${data}= Create Dictionary command=start
152+
${headers}= Create Dictionary Origin=http://localhost
103153
${response}= POST
104154
... ${API_URL}/plugin-manager/${id}/execute
155+
... headers=${headers}
105156
... expected_status=${STATUS_BAD_REQUEST}
106157
... json=${data}
107158

@@ -121,23 +172,21 @@ GET /plugin/${author}/${name} with invalid author and name
121172

122173
POST /plugin-manager/{id}/execute with invalid id
123174
${data}= Create Dictionary command=start
175+
${headers}= Create Dictionary Origin=http://localhost
124176
${response}= POST
125177
... ${API_URL}/plugin-manager/invalid/execute
178+
... headers=${headers}
126179
... expected_status=${STATUS_NOT_FOUND}
127180
... json=${data}
128181
Should Be Equal As Strings ${response.json()['code']} Plugin-0001
129182
Should Be Equal As Strings ${response.json()['message']} get plugin error: no plugin matching correlationID invalid
130183

131-
DELETE /plugin-manager/{id} with invalid id
132-
${response}= DELETE ${API_URL}/plugin-manager/3829029 expected_status=${STATUS_INTERNAL_SERVER_ERROR}
133-
Should Be Equal As Strings
134-
... ${response.json()['message']}
135-
... getting plugin 3829029: no plugin matching correlationID 3829029
136-
137184
POST /plugin-manager/{id}/execute with invalid body
138185
${data}= Create Dictionary command=test
186+
${headers}= Create Dictionary Origin=http://localhost
139187
${response}= POST
140188
... ${API_URL}/plugin-manager/invalid/execute
189+
... headers=${headers}
141190
... expected_status=${STATUS_UNPROCESSABLE_ENTITY}
142191
... json=${data}
143192
Should Be Equal As Strings ${response.json()['code']} 606
@@ -155,8 +204,10 @@ POST /plugin-manager/register with invalid id
155204
... home=sunt
156205
... api_spec=culpa enim sint aliqua
157206
... url=oluptate
207+
${headers}= Create Dictionary Origin=http://localhost
158208
${response}= POST
159209
... ${API_URL}/plugin-manager/register
210+
... headers=${headers}
160211
... expected_status=${STATUS_NOT_FOUND}
161212
... json=${data}
162213

@@ -172,9 +223,47 @@ POST /plugin-manager/register with invalid body
172223
... logo=id et sunt irure,
173224
... home=sunt
174225
... api_spec=culpa enim sint aliqua
226+
${headers}= Create Dictionary Origin=http://localhost
175227
${response}= POST
176228
... ${API_URL}/plugin-manager/register
229+
... headers=${headers}
177230
... expected_status=${STATUS_UNPROCESSABLE_ENTITY}
178231
... json=${data}
179232
Should Be Equal As Strings ${response.json()['code']} 602
180233
Should Be Equal As Strings ${response.json()['message']} body.url in body is required
234+
235+
POST /plugin-manager/register with not allowed origin header
236+
${id}= Get Plugin ID From Author and Name massa-labs hello-world
237+
${data}= Create Dictionary
238+
... id=
239+
... url=http://localhost:1234
240+
${headers}= Create Dictionary Origin=http://malicious.example.com
241+
${response}= POST
242+
... ${API_URL}/plugin-manager/register
243+
... headers=${headers}
244+
... expected_status=${STATUS_FORBIDDEN}
245+
... json=${data}
246+
${response_str}= Convert To String ${response.content}
247+
Should Contain ${response_str} Forbidden: Operations restricted to authorized domains
248+
249+
250+
DELETE /plugin-manager/{id} with invalid id
251+
${headers}= Create Dictionary Origin=http://localhost
252+
${response}= DELETE ${API_URL}/plugin-manager/3829029 headers=${headers} expected_status=${STATUS_INTERNAL_SERVER_ERROR}
253+
Should Be Equal As Strings
254+
... ${response.json()['message']}
255+
... getting plugin 3829029: no plugin matching correlationID 3829029
256+
257+
DELETE /plugin-manager/{id} with not allowed origin header
258+
${id}= Get Plugin ID From Author and Name massa-labs hello-world
259+
${headers}= Create Dictionary Origin=http://malicious.example.com
260+
${response}= DELETE ${API_URL}/plugin-manager/${id} headers=${headers} expected_status=${STATUS_FORBIDDEN}
261+
${response_str}= Convert To String ${response.content}
262+
Should Contain ${response_str} Forbidden: Operations restricted to authorized domains
263+
264+
DELETE /plugin-manager/{id} hello-world plugin
265+
${id}= Get Plugin ID From Author and Name massa-labs hello-world
266+
${headers}= Create Dictionary Origin=http://station.massa
267+
${response}= DELETE ${API_URL}/plugin-manager/${id} headers=${headers} expected_status=${STATUS_NO_CONTENT}
268+
${id}= Get Plugin ID From Author and Name massa-labs hello-world
269+
Should Be Equal As Strings ${id} ${EMPTY}

0 commit comments

Comments
 (0)