Installed native module is not executable
- Dominant language
- TypeScript
- Stars
- 7.1k
- Forks
- 641
- Avg merge
- 3d 1h
- Merged PRs (30d)
- 30
Description
### Pre-flight checklist
- [X] I have read the [contribution documentation](https://github.com/electron/forge/blob/main/CONTRIBUTING.md) for this project.
- [X] I agree to follow the [code of conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project uses.
- [X] I have searched the issue tracker for a bug that matches the one I want to file, without success.
### Electron Forge version
6.0.5
### Electron version
v23.1.4
### Operating system
MacOS 13.0 (ARM)
### Last known working Electron Forge version
_No response_
### Expected behavior
I want to extract 7-zip archives using the native module [7zip-min](https://github.com/onikienko/7zip-min).
Expected behaviour: Archive contents are extracted without error.
### Actual behavior
### behavior
Extracting works fine when running it outside of Electron (e.g. `yarn run ts-node src/test.ts`, see example below for code),
but it fails when triggering it from the renderer thread via `ipcRenderer.invoke`:
```
Error occurred in handler for 'run-custom-operation': Error: spawn /Users/me/my-project/.webpack/main/native_modules/mac/arm64/7za EACCES
```
### observation
- The file in question (`.webpack/main/native_modules/mac/arm64/7za`) is owned by `root` and not executable.
- Everything works fine when I first run `yarn start` and wait until the dev server is fully running, then run `chmod +x` on the file
- Running `yarn start` again will reset permissions on the file
### Steps to reproduce
## steps
1. Set up Electron Forge project via [Webpack + Typescript template](https://www.electronforge.io/templates/typescript-+-webpack-template)
2. Install [7zip-min](https://github.com/onikienko/7zip-min)
3. Add code to invoke `_7z.unpack()` (see below)
4. `yarn start`
3. invoke native module operations via `ipcRenderer.invoke` in code, e.g. on click
## code examples
### failing example
```ts
// extract.ts
const extract = async (filePath: string) => {
const osTmpDir = os.tmpdir()
const tmpDir = await fs.promises.mkdtemp(joinPaths(osTmpDir, 'random-tmp'))
return new Promise((resolve, reject) => {
_7z.unpack(filePath, tmpDir, err => {
if (err) return reject(err)
resolve(tmpDir)
})
})
}
// in index.ts
ipcMain.handle('extract', (_: IpcMainInvokeEvent, filePath: string) =>
extract(filePath)
)
// in preload.js
contextBridge.exposeInMainWorld('electronAPI', {
extract: (filePath: string) => ipcRenderer.invoke('extract', filePath),
})
// in web app (e.g. in button click handler)
await window.electronAPI.extract('path/to/archive.7z')
```
### working separate example (without Electron involved, run `yarn run ts-node src/test.ts`)
```ts
import _7z from '7zip-min'
const main = async () => {
return new Promise((resolve, reject) => {
_7z.unpack('arbitrary_file.7z', 'arbitrary_dir', err => {
if (err) return reject(err)
resolve()
})
})
}
main()
```
### Additional information
_No response_
Contributor guide
Assessment
This issue has not been assessed yet.