Skip to content

Commit

Permalink
Add skip-firewall-check option (#231)
Browse files Browse the repository at this point in the history
* Add skip-firewall-check

* Update README

* Add skipFirewallCheck to IActionInputs
  • Loading branch information
zijchen authored Jun 26, 2024
1 parent 55b0e52 commit 6af8ff5
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 12 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ The definition of this GitHub Action is in [action.yml](https://github.com/Azure

# optional additional dotnet build options when building a database project file
build-arguments:

# optional, set this to skip checking if the runner has access to the server. Default is false.
skip-firewall-check:
```
## 🎨 Samples
Expand Down
44 changes: 44 additions & 0 deletions __tests__/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,48 @@ describe('main.ts tests', () => {
expect(setFailedSpy).toHaveBeenCalledWith(`Action ${actionName} is invalid. Supported action types are: Publish, Script, DriftReport, or DeployReport.`);
});
});

describe('validate firewall rule check depending on skip-firewall-check value', () => {
const inputs = [
[ 'skip-firewall-check is false, firewall rule should be checked', false, true ],
[ 'skip-firewall-check is true, firewall rule should not be checked', true, false]
];

it.each(inputs)('%s', async (testName, skipFirewallCheckValue, firewallRuleCheckRan) => {
const resolveFilePathSpy = jest.spyOn(AzureSqlActionHelper, 'resolveFilePath').mockReturnValue('./TestSqlFile.sql');
const getInputSpy = jest.spyOn(core, 'getInput').mockImplementation((name, options) => {
switch (name) {
case 'connection-string': return 'Server=testServer.database.windows.net;Initial Catalog=testDB;User Id=testUser;Password=placeholder;';
case 'path': return './TestSqlFile.sql';
case 'arguments': return '-v FakeSqlcmdArgument';
default: return '';
}
});
const getBooleanInputSpy = jest.spyOn(core, 'getBooleanInput').mockImplementation((name, options) => {
switch (name) {
case 'skip-firewall-check': return Boolean(skipFirewallCheckValue);
default: return false;
}
});
const detectIPAddressSpy = jest.spyOn(SqlUtils, 'detectIPAddress').mockResolvedValue('');
const executeSpy = jest.spyOn(AzureSqlAction.prototype, 'execute').mockResolvedValue();
const removeFirewallRuleSpy = jest.spyOn(FirewallManager.prototype, 'removeFirewallRule');

await run();

expect(AzureSqlAction).toHaveBeenCalled();
expect(getInputSpy).toHaveBeenCalledTimes(4);
expect(getBooleanInputSpy).toHaveBeenCalled();
expect(resolveFilePathSpy).toHaveBeenCalled();
expect(executeSpy).toHaveBeenCalled();

if (Boolean(firewallRuleCheckRan)) {
expect(detectIPAddressSpy).toHaveBeenCalled();
} else {
expect(detectIPAddressSpy).not.toHaveBeenCalled();
}
expect(removeFirewallRuleSpy).not.toHaveBeenCalled();

});
});
})
4 changes: 4 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ inputs:
build-arguments:
description: 'In case of a .sqlproj file, additional arguments that will be applied to dotnet build when building the database project.'
required: false
skip-firewall-check:
description: 'Skip the firewall check when connecting to the Azure SQL Server.'
required: false
default: false
runs:
using: 'node20'
main: 'lib/main.js'
2 changes: 1 addition & 1 deletion lib/main.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/AzureSqlAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export interface IActionInputs {
connectionConfig: SqlConnectionConfig;
filePath: string;
additionalArguments?: string;
skipFirewallCheck: boolean;
}

export interface IDacpacActionInputs extends IActionInputs {
Expand Down
27 changes: 16 additions & 11 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,17 @@ export default async function run() {
const inputs = getInputs();
const azureSqlAction = new AzureSqlAction(inputs);

const runnerIPAddress = await SqlUtils.detectIPAddress(inputs.connectionConfig);
if (runnerIPAddress) {
let azureResourceAuthorizer = await AuthorizerFactory.getAuthorizer();
let azureSqlResourceManager = await AzureSqlResourceManager.getResourceManager(inputs.connectionConfig.Server, azureResourceAuthorizer);
firewallManager = new FirewallManager(azureSqlResourceManager);
await firewallManager.addFirewallRule(runnerIPAddress);
// Unless skip-firewall-check is set to true, check if the runner's IP address is allowed to connect to the server
if (inputs.skipFirewallCheck !== true) {
const runnerIPAddress = await SqlUtils.detectIPAddress(inputs.connectionConfig);
if (runnerIPAddress) {
let azureResourceAuthorizer = await AuthorizerFactory.getAuthorizer();
let azureSqlResourceManager = await AzureSqlResourceManager.getResourceManager(inputs.connectionConfig.Server, azureResourceAuthorizer);
firewallManager = new FirewallManager(azureSqlResourceManager);
await firewallManager.addFirewallRule(runnerIPAddress);
}
}

await azureSqlAction.execute();
}
catch (error) {
Expand Down Expand Up @@ -71,7 +75,8 @@ function getInputs(): IActionInputs {
actionType: ActionType.SqlAction,
connectionConfig: connectionConfig,
filePath: filePath,
additionalArguments: core.getInput('arguments') || undefined
additionalArguments: core.getInput('arguments') || undefined,
skipFirewallCheck: core.getBooleanInput('skip-firewall-check')
};

case Constants.dacpacExtension:
Expand All @@ -84,7 +89,8 @@ function getInputs(): IActionInputs {
connectionConfig: connectionConfig,
filePath: filePath,
sqlpackageAction: AzureSqlActionHelper.getSqlpackageActionTypeFromString(action),
additionalArguments: core.getInput('arguments') || undefined
additionalArguments: core.getInput('arguments') || undefined,
skipFirewallCheck: core.getBooleanInput('skip-firewall-check')
} as IDacpacActionInputs;

case Constants.sqlprojExtension:
Expand All @@ -98,11 +104,10 @@ function getInputs(): IActionInputs {
filePath: filePath,
buildArguments: core.getInput('build-arguments') || undefined,
sqlpackageAction: AzureSqlActionHelper.getSqlpackageActionTypeFromString(action),
additionalArguments: core.getInput('arguments') || undefined
additionalArguments: core.getInput('arguments') || undefined,
skipFirewallCheck: core.getBooleanInput('skip-firewall-check')
} as IBuildAndPublishInputs;

break;

default:
throw new Error(`Invalid file type provided as input ${filePath}. File must be a .sql, .dacpac, or .sqlproj file.`)
}
Expand Down

0 comments on commit 6af8ff5

Please sign in to comment.