Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
9c24074
feat(storage): add IpFilter support to bucket metadata
thiyaguk09 Jun 8, 2026
bda0d1b
test(storage): add unit for bucket ipFilter metadata management
thiyaguk09 Jun 8, 2026
e469440
test(storage): add system tests for bucket ipFilter metadata configur…
thiyaguk09 Jun 9, 2026
a065dbd
refactor: restrict IpFilter mode to specific union types and allow nu…
thiyaguk09 Jun 9, 2026
991c863
fix: handle destroyed FileWriteStream in upload pipeline and update t…
thiyaguk09 Jun 9, 2026
78d047d
chore: add postinstall script to patch yargs for cjs compatibility
thiyaguk09 Jun 9, 2026
17af3a1
chore: upgrade yargs to v18.0.0 and remove the obsolete yargs patchin…
thiyaguk09 Jun 9, 2026
96bbd56
chore: downgrade yargs dependency to version 17.3.1
thiyaguk09 Jun 9, 2026
f136b64
refactor: remove yargs shimming logic and clean up File stream error …
thiyaguk09 Jun 12, 2026
2389a61
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jun 12, 2026
fcbcdf2
test: update ipFilter test configuration and refine bucket metadata t…
thiyaguk09 Jun 12, 2026
b140f4e
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jun 15, 2026
d52bd4e
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jun 16, 2026
acacc92
test: update ipFilter test cases to verify clearing CIDR ranges and l…
thiyaguk09 Jun 16, 2026
91c4721
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jun 17, 2026
82ef42d
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jun 18, 2026
9b96dee
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jun 18, 2026
790fd69
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jun 18, 2026
3ccd76d
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jun 19, 2026
11b10f0
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jun 22, 2026
b9db610
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jun 23, 2026
faf97d4
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jun 23, 2026
0dcb2dc
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jun 24, 2026
d2ecac7
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jun 24, 2026
09fad64
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jun 25, 2026
c1d68c1
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jun 25, 2026
9450d9e
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jun 26, 2026
255bd03
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jun 29, 2026
3b48981
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jun 30, 2026
84ce69b
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jul 1, 2026
cecb043
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jul 3, 2026
80eb01d
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jul 7, 2026
636192e
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jul 8, 2026
eef69b7
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jul 9, 2026
b74cc2d
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jul 10, 2026
3512197
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jul 21, 2026
8cf3a71
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jul 22, 2026
e4bac2b
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jul 23, 2026
f3fc567
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jul 24, 2026
a69f4c4
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jul 27, 2026
bbf03ef
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jul 28, 2026
8bc0fb4
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jul 28, 2026
17c069a
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jul 29, 2026
32edc2a
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jul 30, 2026
36916cc
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Jul 31, 2026
f1d9527
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Aug 3, 2026
89f5355
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Aug 4, 2026
a6ec34c
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Aug 4, 2026
7091957
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Aug 5, 2026
ec4a5bd
Merge branch 'main' into feat/bucket-ip-filter
Dhriti07 Aug 5, 2026
f843afa
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Aug 5, 2026
218a5a7
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Aug 5, 2026
051bbd7
Merge branch 'main' into feat/bucket-ip-filter
thiyaguk09 Aug 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions handwritten/storage/src/bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,47 @@ export interface EncryptionEnforcementConfig {
restrictionMode?: 'NotRestricted' | 'FullyRestricted';
readonly effectiveTime?: string;
}

/**
* Configuration for a bucket's IP Filter.
*
* @example
* ```
* const {Storage} = require('@google-cloud/storage');
* const storage = new Storage();
* const bucket = storage.bucket('my-bucket');
*
* const metadata = {
* ipFilter: {
* mode: 'Enabled',
* publicNetworkSource: {
* allowedIpCidrRanges: ['192.168.1.1/32']
* }
* }
* };
*
* bucket.setMetadata(metadata, (err, apiResponse) => {
* if (err) {
* console.error(err);
* } else {
* console.log('IP filter updated successfully.');
* }
* });
* ```
*/
export interface IpFilter {
mode?: 'Enabled' | 'Disabled';
publicNetworkSource?: {
allowedIpCidrRanges?: string[];
};
vpcNetworkSources?: {
network?: string;
allowedIpCidrRanges?: string[];
}[];
allowAllServiceAgentAccess?: boolean;
allowCrossOrgVpcs?: boolean;
}

export interface BucketMetadata extends BaseMetadata {
acl?: AclMetadata[] | null;
autoclass?: {
Expand Down Expand Up @@ -361,6 +402,7 @@ export interface BucketMetadata extends BaseMetadata {
lockedTime?: string;
};
};
ipFilter?: IpFilter | null;
labels?: {
[key: string]: string | null;
};
Expand Down
76 changes: 75 additions & 1 deletion handwritten/storage/system-test/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ interface ErrorCallbackFunction {
}
import {PubSub, Subscription, Topic} from '@google-cloud/pubsub';
import {getDirName} from '../src/util.js';
import {BucketMetadata} from '../src/bucket.js';

class HTTPError extends Error {
code: number;
Expand Down Expand Up @@ -1294,6 +1295,79 @@ describe('storage', function () {
});

describe('bucket metadata', () => {
describe('ipFilter', () => {
let ipFilterBucket: Bucket;

before(async () => {
ipFilterBucket = storage.bucket(generateName());
await ipFilterBucket.create();
});

after(async () => {
await ipFilterBucket.delete().catch(() => { });
});

it('should set ipFilter', async () => {
const metadata: BucketMetadata = {
ipFilter: {
mode: 'Disabled',
publicNetworkSource: {
allowedIpCidrRanges: ['0.0.0.0/0', '::/0'],
},
allowAllServiceAgentAccess: false,
},
};
const [meta] = await ipFilterBucket.setMetadata(metadata);
assert.deepStrictEqual(meta.ipFilter, metadata.ipFilter);
});

it('should get ipFilter', async () => {
const [meta] = await ipFilterBucket.getMetadata();
assert.strictEqual(meta.ipFilter?.mode, 'Disabled');
assert.deepStrictEqual(
meta.ipFilter?.publicNetworkSource?.allowedIpCidrRanges,
['0.0.0.0/0', '::/0']
);
});

it('should update ipFilter', async () => {
const metadata: BucketMetadata = {
ipFilter: {
mode: 'Disabled',
publicNetworkSource: {
allowedIpCidrRanges: ['203.0.113.0/24'],
},
allowAllServiceAgentAccess: false,
},
};
const [meta] = await ipFilterBucket.setMetadata(metadata);
assert.deepStrictEqual(meta.ipFilter, metadata.ipFilter);
});

it('should clear allowedIpCidrRanges', async () => {
const [getMeta] = await ipFilterBucket.getMetadata();
assert.strictEqual(getMeta.ipFilter?.mode, 'Disabled');
assert.deepStrictEqual(
getMeta.ipFilter?.publicNetworkSource?.allowedIpCidrRanges,
['203.0.113.0/24']
);

const metadata: BucketMetadata = {
ipFilter: {
mode: 'Disabled',
publicNetworkSource: {
allowedIpCidrRanges: [],
},
allowAllServiceAgentAccess: false,
},
};
const [meta] = await ipFilterBucket.setMetadata(metadata);
assert.strictEqual(meta.ipFilter?.mode, 'Disabled');
assert.strictEqual(meta.ipFilter?.publicNetworkSource?.allowedIpCidrRanges, undefined);
assert.strictEqual(meta.ipFilter?.allowAllServiceAgentAccess, false);
});
});

it('should allow setting metadata on a bucket', async () => {
const metadata = {
website: {
Expand Down Expand Up @@ -4590,7 +4664,7 @@ describe('storage', function () {
setTimeout(resolve, RETENTION_DURATION_SECONDS * 1000),
);
return Promise.all(
buckets.map(bucket => limit(() => deleteBucketAsync(bucket))),
buckets.map(bucket => limit(() => deleteBucketAsync(bucket).catch(() => {}))),
);
}

Expand Down
129 changes: 128 additions & 1 deletion handwritten/storage/test/bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3692,5 +3692,132 @@ describe('Bucket', () => {
bucket.setMetadata(clearMetadata, assert.ifError);
});
});

describe('ipFilter', () => {
it('should enable ipFilter', done => {
const metadata = {
ipFilter: {
mode: 'Enabled',
publicNetworkSource: {
allowedIpCidrRanges: ['192.168.1.1/32'],
},
},
};

bucket.setMetadata = (metadata_: BucketMetadata) => {
assert.deepStrictEqual(metadata_.ipFilter, metadata.ipFilter);
done();
};

bucket.setMetadata(metadata, assert.ifError);
});

it('should update ipFilter', done => {
const metadata = {
ipFilter: {
mode: 'Enabled',
vpcNetworkSources: [
{
network: 'projects/my-project/global/networks/my-vpc',
allowedIpCidrRanges: ['10.0.0.0/8'],
},
],
},
};

bucket.setMetadata = (metadata_: BucketMetadata) => {
assert.deepStrictEqual(metadata_.ipFilter, metadata.ipFilter);
done();
};

bucket.setMetadata(metadata, assert.ifError);
});

it('should get ipFilter', done => {
const ipFilter = {
mode: 'Enabled',
publicNetworkSource: {
allowedIpCidrRanges: ['192.168.1.1/32'],
},
vpcNetworkSources: [
{
network: 'projects/my-project/global/networks/my-vpc',
allowedIpCidrRanges: ['10.0.0.0/8'],
},
],
allowAllServiceAgentAccess: true,
allowCrossOrgVpcs: true,
};

bucket.getMetadata = () => {
return Promise.resolve([{ipFilter}]);
};

bucket.getMetadata().then((data: any) => {
const [metadata] = data;
assert.deepStrictEqual(metadata.ipFilter, ipFilter);
done();
});
});

it('should clear allowedIpCidrRanges', done => {
const initialIpFilter = {
mode: 'Disabled',
publicNetworkSource: {
allowedIpCidrRanges: ['203.0.113.0/24'],
},
};

const updatedIpFilter = {
mode: 'Disabled',
publicNetworkSource: {
allowedIpCidrRanges: undefined,
},
allowAllServiceAgentAccess: false,
};

bucket.getMetadata = () => {
return Promise.resolve([{ipFilter: initialIpFilter}]);
};

bucket.setMetadata = (metadata: any) => {
assert.deepStrictEqual(metadata.ipFilter.publicNetworkSource.allowedIpCidrRanges, []);

return Promise.resolve([{ipFilter: updatedIpFilter}]);
};

bucket.getMetadata()
.then((data: any) => {
const [getMeta] = data;
assert.strictEqual(getMeta.ipFilter?.mode, 'Disabled');
assert.deepStrictEqual(
getMeta.ipFilter?.publicNetworkSource?.allowedIpCidrRanges,
['203.0.113.0/24']
);

const metadataUpdate = {
ipFilter: {
mode: 'Disabled',
publicNetworkSource: {
allowedIpCidrRanges: [],
},
allowAllServiceAgentAccess: false,
},
};

return bucket.setMetadata(metadataUpdate);
})
.then((data: any) => {
const [meta] = data;
assert.strictEqual(meta.ipFilter?.mode, 'Disabled');
assert.strictEqual(meta.ipFilter?.publicNetworkSource?.allowedIpCidrRanges, undefined);
assert.strictEqual(meta.ipFilter?.allowAllServiceAgentAccess, false);
done();
})
.catch((err: any) => {
done(err);
});
});
});
});
});
});
42 changes: 42 additions & 0 deletions handwritten/storage/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1258,6 +1258,48 @@ describe('Storage', () => {
}
);
});

it('should list buckets with ipFilter summary', done => {
const bucketsResponse = [
{
name: 'bucket-with-filter',
metadata: {
ipFilter: {
mode: 'Enabled',
allowCrossOrgVpcs: true,
allowAllServiceAgentAccess: true
}
}
},
{
name: 'bucket-without-filter',
metadata: {
location: 'US'
}
}
];

storage.getBuckets = () => {
return Promise.resolve([bucketsResponse]);
};

storage.getBuckets().then((data: any) => {
const [buckets] = data;
const filteredBucket = buckets.find((b: any) => b.name === 'bucket-with-filter');
const normalBucket = buckets.find((b: any) => b.name === 'bucket-without-filter');

assert.ok(filteredBucket.metadata.ipFilter);
assert.strictEqual(filteredBucket.metadata.ipFilter.mode, 'Enabled');
assert.strictEqual(filteredBucket.metadata.ipFilter.allowCrossOrgVpcs, true);

assert.strictEqual(normalBucket.metadata.ipFilter, undefined);

done();
})
.catch((err: any) => {
done(err);
});
});
});

describe('getHmacKeys', () => {
Expand Down
Loading